Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ Sub-select from Dictionary based on value type

Tags:

c#

linq

I am trying to sub-select a Dictionary<String, Double> from a Dictionary<String, String>. To do this, I use a IEnumrable<>.Where so sub-select a Dictionary<String, String> (which works), then cast it to Dictionary<String, Double> (doesn't work).

My Code:

//linesTable is an System.data.DataTable object
//...for loop code in here
DataRow row = linesTable.Rows[i]; //Where i is the loop index
Dictionary<String, String> valuesDictionary 
    = row.Table.Columns.Cast<DataColumn>().ToDictionary(
                col => col.ColumnName, 
                col => row.Field<String>(col.ColumnName));
//ATTEMPT #1
/*Dictionary<String, Double> numericValues = valuesDictionary.Where(
                subs => 
                    { 
                        double doubleValue; 
                        return double.TryParse(subs.Value, out doubleValue);                
                    }).Cast<Dictionary<String, Double>>();*/
//ATTEMPT #2
Dictionary<String, Double> numericValues = valuesDictionary.Where(
    subs => {
        double doubleValue;
        return double.TryParse(subs.Value, out doubleValue);
    }
).ToDictionary<String, Double>(
    pair => pair.Key,
    pair => double.Parse(pair.Value));

What am I doing wrong?

The reason I need it in a Dictionary<String, Double> format is because I have a method that takes in this type that I need to pass the dictionary data to.

Thanks in advance!

SIMILAR QUESTIONS: My question is similar to these: http://bit.ly/12qjrmE, http://bit.ly/YmuRHZ and http://bit.ly/XLQNaB, except that I want the subquery to return a Dictionary type as well.

like image 919
Sinker Avatar asked Dec 20 '12 00:12

Sinker


2 Answers

You can't cast a Dictionary<string, string> to a Dictionary<string, double> because it isn't one. You would need to create a new Dictionary instead (or go straight to the Dictionary<string,double> if you don't need the Dictionary<string,string> as Konstantin suggests).

In fact, your code doesn't even really do what you're thinking. The Cast<Dictionary<string,Double>>() that you chained onto the Where() is attempting to cast every item in the IEnumerable to the Dictionary<string, Double>.

I think what you want instead is:

Dictionary<String, Double> numericValues = valuesDictionary
      .Where(
            pair => 
                { 
                    double doubleValue; 
                    return double.TryParse(subs.Value, out doubleValue);                
                })
      .ToDictionary(pair => pair.Key, pair => double.Parse(pair.Value);

That is, for all cases where the double can be parsed, put them in a new Dictionary<string, double>.

Of course, you could use a RegEx, or something similar to make the Where prettier, but the essential point is that Cast<>() is to cast each item in the sequence, it doesn't cast the sequence as a whole. Further, you can't cast the sequence as a whole, because a Dictionary<string,string> is not a Dictionary<string,double>.

Thus, you need a new Dictionary, and using ToDictionary() is one option to get there...

like image 67
James Michael Hare Avatar answered Nov 10 '22 12:11

James Michael Hare


If you don't need Dictionary<String, String>, you could make it at once:

Dictionary<String, Double> valuesDictionary =
    row.Table.Columns.Cast<DataColumn>()
                     .Where(col =>
                     {
                         double d;
                         return double.TryParse(row.Field<String>(col.ColumnName), out d);
                     })
                     .ToDictionary(
                         col => col.ColumnName,
                         col => double.Parse(row.Field<String>(col.ColumnName)));
like image 42
horgh Avatar answered Nov 10 '22 14:11

horgh