我正在尝试在C#中开发一个简单的应用程序来计算列表框中重复项的数量。我需要计算所有重复项的数量,并显示最重复的前3个元素的等级后缀。例如,假设一个列表有7个元素称为'apple',6个元素称为'pear',4个元素称为'peach',3个元素称为'orange',在此过程之后,它应该将列表显示为:
apple (7) pear (6) peach (4) orange
答案 0 :(得分:2)
由于我们不知道您使用的数据源,因此这是一个可以帮助您入门的通用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() }).Take(3);
这将返回包含前3项中name and rank
的对象集合。
当然,您可以使用填充ListBox的每个数据源替换items
数组,如果这些项不仅仅是简单的字符串,而是更复杂的项,您可以适当地调整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个项目显示排名的项目填充列表框。
答案 1 :(得分:0)
这是使用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最终以惊人的速度变慢(大约1000倍的速度),以便在任何地方和任何地方使用Linq开绿灯,但当然在这一个地方它非常好。 / p>
我认为道德一直是测试,测试,测试。
以下是添加到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方法似乎每次都很突出。这是美国宪法(所有七篇文章和签名)。这可能是由于声明包含大量重复词(“他有......”)。
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<string, int>(items.Length / 2);
foreach (string item in items)
{
if (!ranking.ContainsKey(item))
ranking[item] = 1;
else
ranking[item]++;
}
var list = new List<KeyValuePair<string, int>>(ranking);
list.Sort((a, b) => b.Value.CompareTo(a.Value));
foreach (KeyValuePair<string, int> 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;
}
}