4

I have the following query that takes a DataTable and counts the number of times a value appears in the countField column.

var countField = "class"
var query = from row in myDataTable.AsEnumerable()
            group row by row.Field<string>(countField)
            into sumry
            orderby sumry.Count() descending
            select new
            {
                Text = sumry.Key,
                CountofRows = sumry.Count()
            };

This works as expected, unless the column contains decimal values. I am not familiar enough with linq to know what to change to allow it to count the instances of a decimal value.

How can I make this statement more robust so it will work for any data type contained in the indicated column?

davids
  • 5,397
  • 12
  • 57
  • 94

2 Answers2

4

You could just fetch the value using DataRow's indexer and convert it to string:

var query = from row in myDataTable.AsEnumerable()
        group row by row[countField].ToString()
        into sumry
        orderby sumry.Count() descending
        select new
        {
            Text = sumry.Key,
            CountofRows = sumry.Count()
        };

This should work as expected for all types.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • I figured it would be easy. I tried converting it to a string, but not with the indexer. This works perfectly. Thanks! – davids Nov 14 '14 at 18:35
2

You can get the type of the column and use reflection to invoke Field<T>(). (see this answer for invoking generic methods: https://stackoverflow.com/a/232621/409259)

var columnType = myDataTable.Columns[countField].DataType;
var method = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(string) });
var generic = method.MakeGenericMethod(columnType);

var query = from row in myDataTable.AsEnumerable()
            group row by generic.Invoke(null, new object[] { row, countField })
            into sumry
            orderby sumry.Count() descending
            select new
            {
                Text = sumry.Key,
                CountOfRows = sumry.Count()
            };
Community
  • 1
  • 1
Jeff Ogata
  • 56,645
  • 19
  • 114
  • 127
  • Does this offer an advantage over the answer by Selman22? It seems more complex, which isn't always bad, but I don't see what the extra code offers? – davids Nov 14 '14 at 23:11
  • 1
    It only matters if `ToString()` would lose information that would distinguish different values. For example, `DateTime.ToString()` formats times to the second. If you needed to group by times at the millisecond, it wouldn't work for you. I think for all other primitive types, and `DateTime` to the second, `ToString` would be fine. For complex types, you would have to keep this in mind to make sure the grouping works as desired. – Jeff Ogata Nov 15 '14 at 01:51