views:

329

answers:

1

Hi, I need to calculate a sum of product of two fields. This will be used for average weighted price. avgPrice = sum( price*volume) / sum(volume). Both price1 and price2 return error "Specified cast is not valid."

     var result3 = from sym in dataTableAsEnumerable()
                   group sym by new { symbol = sym["symbol"] } into grouped
                   select new
                   {
                      //             SYMBOL = sym.Field<string>("symbolCAN"),
                      SYMBOL = grouped.Key.symbol,
                      tradeTimeMin = grouped.Min(e => e["tradeTimeMin"]),
                      tradeTimeMax = grouped.Max(e => e["tradeTimeMax"]),
                      volume = grouped.Sum(e => (int)e["volume"] ),
                      price1 = grouped.Sum(e => (double)e["volume"] * (double)e["symbol"]) / grouped.Sum(e => (double)e["volume"]),
                      price2 = grouped.Sum(e => ( e.Field<decimal>("volume") * e.Field<decimal>("symbol")))


                   };
A: 

The problem you're seeing is related to getting the values out of the DataRow. It looks like volume is an int and symbol is a double, but in your error lines you're using one or the other as a different type. A comparable example would be trying to do this:

object o = 3.0; // double
decimal m = (decimal)o;

This will fail because you're trying to unbox a double as a decimal. On the other hand, this works fine:

object o = 3.0; // double
double d = (double)o;
decimal m = (decimal)d;

To fix your example, you need to first cast the value to the correct type, then cast accordingly (or just fall back on implicit casts):

    ...
    price = grouped.Sum(e => e.Field<int>("volume") * e.Field<double>("symbol")) /
            grouped.Sum(e => e.Field<int>("volume"))
    ...

Or using an anonymous type to make your final select more readable:

...
let data = grouped.Select(e => new {
   Volume = e.Field<int>("volume"),
   Symbol = e.Field<double>("symbol")
})
select new
{
    ...
    price = data.Sum(x => x.Volume * x.Symbol) / data.Sum(x => x.Volume)
    ...
};
dahlbyk
Hi dahlbyk. Thank you for your answer. I was indeed mixing types.This worked well: averagePrice = grouped.Sum(e => (e.Field<int>("volume") * e.Field<decimal>("price"))) / grouped.Sum(e => (int)e["volume"])
Sin
Glad to help. For your future reference, the Field<T> extension method is really only useful for nullable types because it handles DBNull. For value types, you might as well just cast directly.
dahlbyk
Well, as you might have noticed, I am brand new in LINQ. Just trying to complete a project. To understand more complex concepts, I will need to do some serious learning. Your answer helped me over the first bump. Thanks again, Sin.
Sin