1

LINQ を使用した並べ替えでシーケンスをグループ化およびカウントするための最適なパフォーマンス方法を探しています。500 MB を超えるファイルを処理するので、そのタスクではパフォーマンスが最も重要な鍵となります。

List<int[]> num2 = new List<int[]>();
num2.Add(new int[] { 35, 44 });
num2.Add(new int[] { 200, 22 });
num2.Add(new int[] { 35, 33 });
num2.Add(new int[] { 35, 44 });
num2.Add(new int[] { 3967, 11 });
num2.Add(new int[] { 200, 22 });
num2.Add(new int[] { 200, 2 });

結果は次のようになります。

[35,   44]  => 2
[200,  22] => 2
[35,   33] => 1
[35,   44] => 1
[3967, 11] => 1
[200,  2 ] => 1

私はこのようなことをしました:

        Dictionary<int[], int> result2 = (from i in num2
                                       group i by i into g
                                       orderby g.Count() descending
                                       select new { Key = g.Key, Freq = g.Count() })
                          .ToDictionary(x => x.Key, x => x.Freq);

        SetRichTextBox("\n\n Second grouping\n");

        foreach (var i in result2)
        {
            SetRichTextBox("\nKey: ");
            foreach (var r in i.Key)
            {
                SetRichTextBox(r.ToString() + "  ");
            }

            SetRichTextBox("\n  Value: " + i.Value.ToString());

        }

しかし、それは正しく機能していません。何か助けはありますか?

4

2 に答える 2

1

長さ 2 の配列の場合、これは機能します。

num2.GroupBy(a => a[0])
    .Select(g => new { A0 = g.Key, A1 = g.GroupBy(a => a[1]) })
    .SelectMany(a => a.A1.Select(a1 => new { Pair = new int[] { a.A0, a1.Key }, Count = a1.Count() }));

これで最適なパフォーマンスが得られるはずです。.AsParallel()最初の Select ステートメントの後に句を試すこともできます。

この戦略 (配列の n 番目の要素で連続してグループ化) は、任意の長さの配列に一般化されます。

var dim = 2;

var tuples = num2.GroupBy(a => a[0])
    .Select(g => new Tuple<int[], List<int[]>>(new [] { g.Count(), g.Key }, g.Select(a => a.Skip(1).ToArray()).ToList()));

for (int n = 1; n < dim; n++)
{
    tuples = tuples.SelectMany(t => t.Item2.GroupBy(list => list[0])
        .Select(g => new Tuple<int[], List<int[]>>(new[] { g.Count() }.Concat(t.Item1.Skip(1)).Concat(new [] { g.Key }).ToArray(), g.Select(a => a.Skip(1).ToArray()).ToList())));
}

var output = tuples.Select(t => new { Arr = string.Join(",", t.Item1.Skip(1)), Count = t.Item1[0] })
    .OrderByDescending(o => o.Count)
    .ToList();

の出力を生成します

Arr = "35, 44", Count = 2
Arr = "200, 22", Count = 2
Arr = "35, 33", Count = 1
Arr = "200, 2", Count = 1
Arr = "3967, 11", Count = 1

あなたの例では。高次元でテストしてみましょう。:)

連続するグループ化は独立しているため、これらのクエリをそれほど困難なく並列化できるはずです。

于 2013-10-23T20:39:45.473 に答える
0

次のようなことができます。

var results = from x in nums
              group x by new { a = x[0], b = x[1] } into g
              orderby g.Count() descending
              select new
              {
                  Key = g.Key,
                  Count = g.Count()
              };

foreach (var result in results)
    Console.WriteLine(String.Format("[{0},{1}]=>{2}", result.Key.a, result.Key.b, result.Count));

秘訣は、配列自体ではなく、配列内の値を比較する方法を考え出すことです。

別の方法 (およびおそらくより良いオプション) は、データを からint[]カスタム タイプに変換し、そのカスタム タイプの等値演算子をオーバーライドしてから だけgroup x by x into gにすることですが、本当に行き詰っている場合は、これでうまくいきますint[]

于 2013-10-23T20:27:28.247 に答える