1

私は式を持っています:

Records.OrderBy(o => o.TIME).Where((o, i) => i % interval == 0).ToList();

これは、データレコードの大きなリストを取得して、それを小さなリストに切り詰めるのに問題ありません。(interval はスキップするレコードの数です)。問題は、フィールドをスキップするだけでなく、いくつかのフィールドを平均化したいということです。巨大なループを作らずにこれを行う方法がわかりません。各データ レコードには約 90 のフィールドがあることに注意してください。アイデア?

編集: n 番目のレコードごとに正確にスキップし、2 つの特定のフィールド (緯度と経度 (10 進数として格納)) を平均し、他の 88 フィールドはそのままにしておくことができるようにしたいと考えています。

編集:私はから行きたいです

    timelat longmany other fields
    1   2   3   field1
    2   3   4   field1
    3   4   5   field1
    4   5   6   field1
    5   6   7   field1
    6   7   8   field1
    7   8   9   field1
    8   9   10  field1
    9   10  11  field1
    10  11  12  field1
    11  12  13  field1
    12  13  14  field1

に:

    timelat     long    other fields            
    3   3   4   field1
    6   6   7   field1
    9   9   10  field1
    12  12  13  field1
4

3 に答える 3

3

私の理解が正しければ、多数のアイテムを少数の同じサイズの「バケット」にグループ化し、各バケットで一部のフィールドを集計 (平均化など) し、一部のフィールドをスキップ (つまり、最後のアイテムから取得) する必要があります。バケツ)。

これができるかどうかを検討してください:

Records
.ToBuckets(interval)
.Select(bucket => new Record {
     Time = bucket.Last().Time,
     Count = bucket.Count,
     Lat = bucket.Average(x => x.Lat), 
     Long = bucket.Average(x => x.Long),
     Other = bucket.First().Other
}
.ToList()

これが必要な場合は、ToBuckets メソッドを作成するだけで済みます。これは、はるかに単純な (そして一般的な!) 問題です。

public static IEnumerable<IList<T>> ToBuckets<T>(this IEnumerable<T> source, int size)
{
    var bucket = new List<T>(size);
    foreach (var item in source)
    {
        bucket.Add(item);
        if (bucket.Count == size) {
           yield return bucket;
           bucket = new List<T>(size); // or you can use the same one if you're careful
    }

    if (bucket.Count > 0) yield return bucket;
}

(上記は例をサポートするための拡張メソッドとして提供されていますが、これはもちろん通常のメソッドでもかまいません)。

于 2012-07-14T16:51:16.940 に答える
2

Where 句に貼り付けることができるはずです。少し見苦しいですが、次のようになります。

[編集: あなたの編集から、あなたが何か少し違うものを望んでいたことがわかりました。このコードはそれに応じて編集されています]。

decimal latSum = 0;
decimal longSum = 0;
int count = 0;

var recordList = Records
    .OrderBy(o => o.TIME)
    .Where((o, i) => {
        if (i % interval == 0)
        {
            // Modify the record in place (hope that's OK)
            o.Lat = (o.Lat + latSum) / (count + 1);
            o.Long = (o.Long + longSum) / (count + 1);
            latSum = longSum = count = 0;
            return true;
        }

        latSum += o.Lat;
        longSum += o.Long;
        count++;
        return false;
    })
    .ToList();
于 2012-07-14T16:32:57.907 に答える
2

特定のレコードを平均に含めたい場合は、そのレコードに触れる必要があります。 明示的に実行しているか、Linq が舞台裏で実行しているかにかかわらず、何かがすべてのレコードをループする必要があります。

指定された Linq 式は 1 つのものしか返すことができません。

現在使用している Linq 式は、フィルター処理されたリストを返します。

すべてのレコードを平均化するには、2 つ目の Linq 式 (または独自のループ) が必要になります。

var avg = Records.Average(r => r.FieldToAverage);

私はあなたが何を意味したのか分かりません

各データ レコードには約 90 のフィールドがあることに注意してください。

特定のレコード内のフィールドを平均化する必要がありますか? もしそうなら、それらはどのようなデータ型ですか? これらのフィールドをすべて列挙する既存の方法はありますか? そうでない場合は、各フィールドに明示的にアクセスするか、リフレクションを使用して (関連する) フィールドを列挙する必要があります。

于 2012-07-14T16:13:30.110 に答える