2

2 つの配列があるとします。

DateTime[] wDates = new DateTime[20000];
double[] wValues = new double[20000];

これらの 2 つの配列は両方とも順番に並べられます。つまり、int i が指定されます。wValues[i] は日付 wDates[i] です。

日付の月が 1 月である wValues の平均値を取得する必要があるとします。

標準ループを使用すると、次のようになります。

double wAvg = 0.0;
int wDataCount = 0;
for (int i=0; i < 20000; i++)
  if (wDates[i].Month == 1)
  {
    wAvg += wValues[i];
    wDataCount++;
  }

if (wDataCount > 0)
  wAvg /= wDataCount;

LINQでこれを行う方法を知りたいですか?両方の値を含む構造体/クラス DateDouble を作成してから、次のようなことを行うことができます。

List<DateDouble> wListData = new List<DateDouble>();
Add the items...
double wAvg = (from d in wListData
               where d.Date.Month == 1
               select d.Value).Average();

しかし、何千もの DateDouble オブジェクトを作成すると、1 日に何千万回も作成すると、メモリのオーバーヘッドが大きくなります。一時オブジェクトでも同じことが起こり、'index' を使用して配列のインデックスを結合しようとすると、ひどいパフォーマンスが発生します。

LINQ でこれを達成するためのより良い方法はありますか?

ありがとう、MM

4

3 に答える 3

3

さて、Zip演算子を使用して物事を簡単にすることができます。

var average = wDates.Zip(wValues, (date, value) => new { date, value })
                    .Where(pair => pair.date.Month == 1)
                    .Average(pair => pair.value);

それでも、ペアごとに匿名型のインスタンスが 1 つ作成されますが、個人的にはそれを手放して、コストがかかりすぎると考える前にパフォーマンスを測定したいと思います。これはストリーミング方式で動作することに注意してください。そのため、大量のガベージが生成されますが、一度に必要なメモリの合計はわずかです。

独自のペア構造体を作成することでより効率的にすることができます...これにより、余分なオブジェクトの作成が回避されますが、少し面倒になります。ただし、それほど悪くはありません。

// The normal Tuple types are classes.
public struct TupleValue<T1, T2>
{
    private readonly T1 item1;
    private readonly T2 item2;

    public T1 Item1 { get { return item1; } }
    public T2 Item2 { get { return item2; } }

    public TupleValue(T1 item1, T2 item2)
    {
        this.item1 = item1;
        this.item2 = item2;
    }
}

var average = wDates.Zip(wValues, (date, value) => 
                                   new TupleValue<DateTime, double>(date, value))
                    .Where(pair => pair.Item1.Month == 1)
                    .Average(pair => pair.Item2);

ただし、最初のアプローチが2つのコストがかかることを証明したでのみ、これを行います。

于 2012-05-17T16:08:49.207 に答える
2

述語のインデックスも考慮する IEnumerable.Where() 拡張メソッドのオーバーロードされたバージョンがあります。

double average = wValues.Where((d, i) => wDates[i].Month == 1).Average();
于 2012-05-17T17:13:37.153 に答える
0

何かのようなもの:

double wAvg = wDates.Select((d,i) => new { Month = d.Month, Index = i })
                    .Where(x => x.Month == 1)
                    .Select(x => wValues[i])
                    .Average();

とにかく、この場合、その匿名型の N インスタンスも作成します。

于 2012-05-17T16:15:39.357 に答える