给定一个有序的字符串集合:
var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" };
Run Code Online (Sandbox Code Playgroud)
使用LINQ创建字符串字典到集合中该字符串的出现次数:
IDictionary<string,int> stringToNumOccurrences = ...;
Run Code Online (Sandbox Code Playgroud)
最好一次通过琴弦收集......
var dico = strings.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
Run Code Online (Sandbox Code Playgroud)
Timwi /达林的建议将在单传过来的原始集合执行此,但它会创建用于分组多个缓冲区.LINQ并不是非常擅长这种计数,这样的问题是我编写Push LINQ的最初动机.您可能希望阅读我的博客文章,了解有关为什么LINQ在这里效率不高的详细信息.
推LINQ和相同想法的更令人印象深刻的实现 - Reactive Extensions - 可以更有效地处理这个问题.
当然,如果你真的不太关心额外的效率,请GroupBy回答:)
编辑:我没有注意到你的琴弦是订购的.这意味着你可以多更有效,因为你知道,一旦你看到串x,然后y字符串,如果X和Y是不同的,你永远也不会再见到X.LINQ中没有任何内容可以让这更容易,但你可以很容易地自己做:
public static IDictionary<string, int> CountEntries(IEnumerable<string> strings)
{
var dictionary = new Dictionary<string, int>();
using (var iterator = strings.GetEnumerator())
{
if (!iterator.MoveNext())
{
// No entries
return dictionary;
}
string current = iterator.Current;
int currentCount = 1;
while (iterator.MoveNext())
{
string next = iterator.Current;
if (next == current)
{
currentCount++;
}
else
{
dictionary[current] = currentCount;
current = next;
currentCount = 1;
}
}
// Write out the trailing result
dictionary[current] = currentCount;
}
return dictionary;
}
Run Code Online (Sandbox Code Playgroud)
这是O(n),除了写入值之外,不涉及字典查找.另一种实现方式是使用foreach和current从null开始的值......但最终在其他几种方式上变得非常狡猾.(我已经尝试过了:)当我需要第一个值的特殊情况处理时,我通常会使用上面的模式.
实际上你可以用LINQ使用Aggregate,但它会非常讨厌.