リストボックス内の重複をカウントする

.net c# duplicates listbox
リストボックス内の重複をカウントする

リストボックス内の重複の数を数えるために、C#で簡単なアプリケーションを開発しようとしています。 重複の数をすべてカウントし、最も重複している上位3つの要素にランクサフィックスを表示する必要があります。 たとえば、リストに「apple」と呼ばれる7つの要素、「pear」と呼ばれる6つの要素、「peach」と呼ばれる4つの要素、および「orange」と呼ばれる3つの要素があるとします。

apple (7)
pear (6)
peach (4)
orange

  0  0


ベストアンサー

使用しているデータソースがわからないので、ここから始めましょう。

string[] items = { "apple", "pear", "peach", "apple", "orange", "peach", "apple" };

var ranking = (from item in items
               group item by item into r
               orderby r.Count() descending
               select new { name = r.Key, rank = r.Count() }).Take(3);

これは、上位3つのアイテムの「名前とランク」を含むオブジェクトのコレクションを返します。

もちろん、ここの `items`配列を、ListBoxを埋めるために使用しているすべてのデータソースで置き換えます。アイテムが単なる文字列ではなく、より複雑なアイテムの場合、LINQクエリを適切に調整します。

上のフォームのように、リストボックスにデータを入力する上記の例です。

  string[] items = { "apple", "pear", "peach", "apple", "orange", "peach", "apple" };

  var ranking = (from item in items
                 group item by item into r
                 orderby r.Count() descending
                 select new { name = r.Key, rank = r.Count() }).ToArray();

  for (int i = 0; i < ranking.Length; ++i)
  {
    var item = ranking[i];
    if (i < 3)
    {
      listBox1.Items.Add(string.Format("{0} ({1})", item.name, item.rank));
    }
    else
    {
      listBox1.Items.Add(item.name);
    }
  }

これは最初の例と同じですが、結果を配列に変換し、リストボックスに、ランクを示す最初の3つの項目を持つ項目を設定します。

2


Linqを使用する代わりの方法を次に示します。これは、どちらがより高速に実行されるかを確認するためのタイミングテストとして提示されています。 これらは、1000回の反復で得られた結果です。

Total words: 1324
Min        Max        Mean       Method
5305       22889      5739.182   LinkMethodToArray
5053       11973      5418.355   LinkMethod
3112       6726       3252.457   HashMethod

この場合、LinkMethodは約1.6倍遅いだけです。 パフォーマンスをテストしたLinqコードの多くほど悪くはありませんが、わずか1324ワードでした。

  • 1を編集*

それはソートを追加する前でした。 並べ替えを行うと、Linqメソッドと比較できることがわかります。 もちろん、ハッシュをリストにコピーしてからリストを並べ替えることは、これを行う最も効率的な方法ではありません。 これを改善できます。 思い浮かぶ方法はいくつかありますが、どれも単純ではなく、多くのカスタムコードを記述する必要があります。

すでに利用可能なものを使用し、コードを明確にするため、実際にはLinqが非常に良い選択であると言わざるを得ません。 これにより、Linq。に対する私の意見が変わりました。 少し。 LinqがどこでもどこでもLinqを使用することに緑色の光を与えるために、Linqが悲惨なほど遅くなる(1000倍の速度で遅くなる)他の比較をあまりにも多く見ましたが、確かにこの1つの場所では非常によく輝いています。

道徳は、いつものように、テスト、テスト、テストだと思います。

以下は、HashMethodにソートが追加された値です。

Total words: 1324
Min        Max        Mean       Method
5284       21030      5667.808   LinkMethodToArray
5081       36339      5425.626   LinkMethod
5017       27583      5288.602   HashMethod
  • 2を編集*

いくつかの簡単な最適化(辞書とリストの両方を事前に初期化する)により、HashMethodが少し顕著に高速になります。

Total words: 1324
Min        Max        Mean       Method
5287       16299      5686.429   LinkMethodToArray
5081       21813      5440.758   LinkMethod
4588       8420       4710.659   HashMethod

*編集#3 *

単語セットが大きくなると、それらはさらに均等になります。 実際、Linqの方法は毎回限界を超えているようです。 これがアメリカ合衆国憲法です(7つの記事と署名すべて)。 これは、宣言に多くの繰り返し単語が含まれているためである可能性があります(「彼は…​」)。

Total words: 4545
Min        Max        Mean       Method
13363      36133      14086.875  LinkMethodToArray
12917      26532      13668.914  LinkMethod
13601      19435      13836.955  HashMethod

コード:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        // Declaration.txt is a copy of the Declaration of Independence
        // which can be found here: http://en.wikisource.org/wiki/United_States_Declaration_of_Independence
        string declaration = File.ReadAllText("Declaration.txt");
        string[] items = declaration.ToLower().Split(new char[] { ',', '.', ':', ';', '-', '\r', '\n', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);

        // pre-execute outside timing loop
        LinqMethodToArray(items);
        LinqMethod(items);
        HashMethod(items);

        int iterations = 1000;
        long min1 = long.MaxValue, max1 = long.MinValue, sum1 = 0;
        long min2 = long.MaxValue, max2 = long.MinValue, sum2 = 0;
        long min3 = long.MaxValue, max3 = long.MinValue, sum3 = 0;

        Console.WriteLine("Iterations: {0}", iterations);
        Console.WriteLine("Total words: {0}", items.Length);

        Stopwatch sw = new Stopwatch();

        for (int n = 0; n < iterations; n++)
        {
            sw.Reset();
            sw.Start();
            LinqMethodToArray(items);
            sw.Stop();
            sum1 += sw.ElapsedTicks;
            if (sw.ElapsedTicks < min1)
                min1 = sw.ElapsedTicks;
            if (sw.ElapsedTicks > max1)
                max1 = sw.ElapsedTicks;

            sw.Reset();
            sw.Start();
            LinqMethod(items);
            sw.Stop();
            sum2 += sw.ElapsedTicks;
            if (sw.ElapsedTicks < min2)
                min2 = sw.ElapsedTicks;
            if (sw.ElapsedTicks > max2)
                max2 = sw.ElapsedTicks;

            sw.Reset();
            sw.Start();
            HashMethod(items);
            sw.Stop();
            sum3 += sw.ElapsedTicks;
            if (sw.ElapsedTicks < min3)
                min3 = sw.ElapsedTicks;
            if (sw.ElapsedTicks > max3)
                max3 = sw.ElapsedTicks;
        }

        Console.WriteLine("{0,-10} {1,-10} {2,-10} Method", "Min", "Max", "Mean");
        Console.WriteLine("{0,-10} {1,-10} {2,-10} LinkMethodToArray", min1, max1, (double)sum1 / iterations);
        Console.WriteLine("{0,-10} {1,-10} {2,-10} LinkMethod", min2, max2, (double)sum2 / iterations);
        Console.WriteLine("{0,-10} {1,-10} {2,-10} HashMethod", min3, max3, (double)sum3 / iterations);
    }

    static void LinqMethodToArray(string[] items)
    {
        var ranking = (from item in items
                       group item by item into r
                       orderby r.Count() descending
                       select new { Name = r.Key, Rank = r.Count() }).ToArray();
        for (int n = 0; n < ranking.Length; n++)
        {
            var item = ranking[n];
            DoSomethingWithItem(item);
        }
    }

    static void LinqMethod(string[] items)
    {
        var ranking = (from item in items
                       group item by item into r
                       orderby r.Count() descending
                       select new { Name = r.Key, Rank = r.Count() });
        foreach (var item in ranking)
            DoSomethingWithItem(item);
    }

    static void HashMethod(string[] items)
    {
        var ranking = new Dictionary(items.Length / 2);
        foreach (string item in items)
        {
            if (!ranking.ContainsKey(item))
                ranking[item] = 1;
            else
                ranking[item]++;
        }
        var list = new List>(ranking);
        list.Sort((a, b) => b.Value.CompareTo(a.Value));
        foreach (KeyValuePair pair in list)
            DoSomethingWithItem(pair);

    }

    static volatile object hold;
    static void DoSomethingWithItem(object item)
    {
        // This method exists solely to prevent the compiler from
        // optimizing use of the item away so that this program
        // can be executed in Release build, outside the debugger.
        hold = item;
    }
}

0


タイトルとURLをコピーしました