[英]Collection of strings to dictionary
给定一个有序的字符串集合:
var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" };
使用LINQ创建字符串字典到集合中该字符串的出现次数:
IDictionary<string,int> stringToNumOccurrences = ...;
最好一次通过琴弦收集......
var dico = strings.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
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;
}
这是O(n),除了在写入值时不涉及字典查找。 另一种实现方式是使用foreach
和一个从null开始的current
值...但最终在其他几种方式上变得非常狡猾。 (我已经尝试过了:)当我需要第一个值的特殊情况处理时,我通常会使用上面的模式。
实际上你可以使用Aggregate
使用LINQ来做到这一点,但它会非常讨厌。
标准LINQ方式是这样的:
stringToNumOccurrences = strings.GroupBy(s => s)
.ToDictionary(g => g.Key, g => g.Count());
如果这是实际的生产代码,我会选择Timwi的回复 。
如果这确实是功课,并且你应该编写自己的实现,那就不应该太难了。 这里只是一些提示,指出你正确的方向:
Dictionary<TKey, TValue>
有一个ContainsKey
方法。 IDictionary<TKey, TValue>
接口的this[TKey]
属性是可设置的; 即,你可以做dictionary[key] = 1
(这意味着你也可以做dictionary[key] += 1
)。 从这些线索中我认为你应该能够“手工”地弄清楚如何做到这一点。
如果您正在寻找一种特别有效 (快速)的解决方案,那么GroupBy
对您来说可能太慢了。 你可以使用一个循环:
var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" };
var stringToNumOccurrences = new Dictionary<string, int>();
foreach (var str in strings)
{
if (stringToNumOccurrences.ContainsKey(str))
stringToNumOccurrences[str]++;
else
stringToNumOccurrences[str] = 1;
}
return stringToNumOccurrences;
这是一个foreach版本,就像Jon提到的那样,他在答案中发现“非常狡猾”。 我把它放在这里,所以有一些具体可谈的内容。
我必须承认,我发现它比Jon的版本更简单,并且无法真正看到它的含义。 乔恩? 任何人?
static Dictionary<string, int> CountOrderedSequence(IEnumerable<string> source)
{
var result = new Dictionary<string, int>();
string prev = null;
int count = 0;
foreach (var s in source)
{
if (prev != s && count > 0)
{
result.Add(prev, count);
count = 0;
}
prev = s;
++count;
}
if (count > 0)
{
result.Add(prev, count);
}
return result;
}
更新为空源添加必要的检查 - 我仍然认为它比Jon更简单:-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.