How to get linq sum of IEnumerable<object>

16,463

Solution 1

You can use expression trees to generate the required add function, then fold over your input list:

private static Func<object, object, object> GenAddFunc(Type elementType)
{
    var param1Expr = Expression.Parameter(typeof(object));
    var param2Expr = Expression.Parameter(typeof(object));
    var addExpr = Expression.Add(Expression.Convert(param1Expr, elementType), Expression.Convert(param2Expr, elementType));
    return Expression.Lambda<Func<object, object, object>>(Expression.Convert(addExpr, typeof(object)), param1Expr, param2Expr).Compile();
}

IEnumerable<object> listValues;
Type elementType = listValues.First().GetType();
var addFunc = GenAddFunc(elementType);

object sum = listValues.Aggregate(addFunc);

note this requires the input list to be non-empty, but it has the advantage of preserving the element type in the result.

Solution 2

If you know the exact type is always going to be a numeric type, you should be able to use something like:

double total = listValues.Sum(v => Convert.ToDouble(v));

This will work because Convert.ToDouble will look for IConvertible, which is implemented by the core numeric types. You are forcing the type to be a double and not the original type, as well.

Share:
16,463
Miguel
Author by

Miguel

Updated on June 17, 2022

Comments

  • Miguel
    Miguel almost 2 years

    How do I get the sum of numbers that are in an IEnumerable collection of objects? I know for sure that the underlying type will always be numeric but the type is determined at runtime.

    IEnumerable<object> listValues = data.Select(i => Convert.ChangeType(property.GetValue(i, null), columnType));
    

    After that I want to be able to do the following (the following has the error:"Cannot resolve method Sum"):

    var total = listValues.Sum();
    

    Any ideas? Thank you.

  • Michael Schnerring
    Michael Schnerring about 11 years
    Keep in mind that this is might throw an InvalidCastException for e.g. strings and other objects!
  • Miguel
    Miguel about 11 years
    @ebeeb - that is true, the code before that call ensures that only numeric types are getting to that point.
  • Miguel
    Miguel about 11 years
    Reed - your solution is simple and works just fine, but I would like to preserve the original type.
  • Reed Copsey
    Reed Copsey about 11 years
    @Mike the problem is there's no way to specify the compile time type to even set the variable properly. You could (potentially) put it in an object, but that won't be very useful...
  • Miguel
    Miguel about 11 years
    your solution works perfectly fine! just trying to understand the whole concept. Thank you.
  • Miguel
    Miguel about 11 years
    In my scenario this solution only works when the underlying type is int.