LINQ prodotto di due campi nella domanda aggregata
Domanda
Ho bisogno di calcolare una somma di prodotto di due campi. Questo sarà utilizzato per prezzo medio ponderato. avgPrice = somma (prezzo * volume) / sum (volume). Sia price1 e l'errore di ritorno price2 "cast specificato non è valido."
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")))
};
Soluzione
Il problema che stai vedendo è legato per ottenere i valori fuori dalla DataRow
. Sembra volume
è un int
e symbol
è un double
, ma nelle vostre linee di errore si sta utilizzando uno o l'altro come un tipo diverso. Un esempio simile sarebbe cercare di fare questo:
object o = 3.0; // double
decimal m = (decimal)o;
Questo non riuscirà perché si sta cercando di unboxing un double
come decimal
. D'altra parte, questo funziona bene:
object o = 3.0; // double
double d = (double)o;
decimal m = (decimal)d;
Per risolvere il tuo esempio, è necessario lanciare per primo il valore per il tipo corretto, poi gettato conseguenza (o semplicemente ripiegare su cast impliciti):
...
price = grouped.Sum(e => e.Field<int>("volume") * e.Field<double>("symbol")) /
grouped.Sum(e => e.Field<int>("volume"))
...
o utilizzando un tipo anonimo per rendere il vostro finale selezionare più leggibile:
...
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)
...
};