0

ラムダ式に関する簡単な質問

次のコードですべての取引の平均を取得したかった。私が使用している式は、((price 1 * qty 1+(price 2 * qty 2).... +(price n * qty n)/(qty 1 + qty 2 + ... + qty n)

次のコードでは、sum関数を使用して(price * qty)の合計を計算しており、複雑さはO(n)になり、もう一度すべてのqtyを合計すると複雑さはO(n)になります。それで、複雑さを使用して両方の合計を見つけることができる方法はありますかO(n)は、両方の結果を計算できる単一のラムダ式を意味します。

forループを使用すると、両方の結果をO(n)の複雑さで計算できます。

class Program
{
    static void Main(string[] args)
    {
        List<Trade> trades = new List<Trade>()
        {
            new Trade() {price=2,qty=2},
            new Trade() {price=3,qty=3}
        };

         ///using lambda
        int price = trades.Sum(x => x.price * x.qty);
        int qty = trades.Sum(x => x.qty);

        ///using for loop
        int totalPriceQty=0, totalQty=0;

        for (int i = 0; i < trades.Count; ++i)
        {
            totalPriceQty += trades[i].price * trades[i].qty;
            totalQty += trades[i].qty;
        }
        Console.WriteLine("Average {0}", qty != 0 ? price / qty : 0);
        Console.Read();
    }
}

class Trade
{
    public int price;
    public int qty;
}

編集:係数がカウントされないことを知っています。質問を言い換えると、ラムダではリスト内の各要素を2回調べますが、forループでは各要素を1回だけ調べます。リスト要素を2回通過する必要がないようにラムダを使用した解決策はありますか?

4

3 に答える 3

3

To expand on BrokenGlass's answer, you could also use an anonymous type as your aggregator like so:

var result = trades.Aggregate( 
                 new { TotalValue = 0L, TotalQuantity = 0L }, 
                 (acc, trade) => new 
                 { 
                     TotalValue = acc.TotalValue + trade.price, 
                     TotalQuantity = acc.TotalQuantity + trade.qty
                 }
             );

There are two small upsides to this approach:

  1. If you're doing this kind of calculation on a large number of trades (or on large trades), it's possible that you would overflow the int that keep track of total value of trades and total shares. This approach lets you specify long as your data type (so it would take longer to overflow).

  2. The object you get back from this aggregation will have more meaningful properties than you would if you simply returned a Trade object.

The big downside is that it's kinda weird to look at.

于 2012-05-15T19:01:02.273 に答える
3

Big-O の複雑度では、定数係数は考慮されません。O(n) + O(n) でも O(n) が得られます。

ラムダで使用することに決めた場合は、Aggregate演算子を使用した例を次に示します。これは不自然に見えますが、従来の for ループよりもお勧めしません。

var result = trades.Aggregate(
    Tuple.Create(0, 0),
    (acc, trade) => 
        Tuple.Create(acc.Item1 + trade.price * trade.qty, acc.Item2 + trade.qty));

int totalPrice = result.Item1;
int totalQuantity = result.Item2;
于 2012-05-15T18:41:56.620 に答える
3

前述のように、1 回反復しても 2 回反復しても、Big-O は変更されません。Linq を使用して1 回だけ反復する場合は、カスタム アグリゲーターを使用できます (同じプロパティに縮小しているTradeため、集約に のインスタンスを使用するだけです)。

var ag = trades.Aggregate(new Trade(), 
                          (agg, trade) => 
                          { 
                            agg.price += trade.price * trade.qty; 
                            agg.qty += trade.qty; 
                            return agg; 
                          });
int price = ag.price;
int qty = ag.qty;

この時点で、個人的には foreach ループまたは既に持っている単純なラムダを使用するだけです - ここでパフォーマンスが重要でない限り (測定してください!)

于 2012-05-15T18:47:52.760 に答える