C# 字符串到字典的集合
给定一个有序的字符串集合:C# 字符串到字典的集合,c#,linq,c#-4.0,C#,Linq,C# 4.0,给定一个有序的字符串集合: var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" }; 使用LINQ创建字符串字典,以确定该字符串在集合中的出现次数: IDictionary<string,int> stringToNumOccurrences = ...; IDictionary StringTonumOccessions=。。。; 最好在字符串集合上进行单次传递…标准LINQ
var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" };
使用LINQ创建字符串字典,以确定该字符串在集合中的出现次数:
IDictionary<string,int> stringToNumOccurrences = ...;
IDictionary StringTonumOccessions=。。。;
最好在字符串集合上进行单次传递…标准LINQ方式如下:
stringToNumOccurrences = strings.GroupBy(s => s)
.ToDictionary(g => g.Key, g => g.Count());
Timwi/Darin的建议将在对原始集合的一次传递中执行此操作,但它将为分组创建多个缓冲区。LINQ真的不太擅长做这种计数,像这样的问题是我写Push LINQ的最初动机。您可能想阅读我的文章,了解更多关于为什么LINQ在这里效率不高的细节 推动LINQ和同样想法的更令人印象深刻的实现——可以更有效地处理这个问题 当然,如果你真的不太在意额外的效率,可以使用
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;
}
公共静态IDictionary CountEntries(IEnumerable字符串)
{
var dictionary=newdictionary();
使用(var iterator=strings.GetEnumerator())
{
如果(!iterator.MoveNext())
{
//没有条目
返回字典;
}
字符串current=迭代器.current;
int currentCount=1;
while(iterator.MoveNext())
{
string next=iterator.Current;
如果(下一个==当前)
{
currentCount++;
}
其他的
{
字典[当前]=当前计数;
当前=下一个;
currentCount=1;
}
}
//写出尾随结果
字典[当前]=当前计数;
}
返回字典;
}
这是O(n),除了在写入值时,不涉及字典查找。另一种实现方法是使用foreach
和一个current
值,该值从null开始。。。但在其他几个方面,这最终是相当令人讨厌的。(我已经尝试过:)当我需要对第一个值进行特殊的案例处理时,我通常使用上述模式
实际上,您可以使用
Aggregate
对LINQ执行此操作,但这将非常糟糕。如果这是实际的生产代码,我会同意
如果这确实是一个家庭作业,并且您需要编写自己的实现,那么它应该不会太难。以下是一些提示,可以为您指明正确的方向:
Dictionary
有一个ContainsKey
方法IDictionary
接口的此[TKey]
属性是可设置的;i、 例如,您可以执行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;
var strings=新字符串[]{“abc”、“def”、“def”、“ghi”、“ghi”、“ghi”、“klm”};
var stringtonumoccurrencess=新字典();
foreach(字符串中的var str)
{
if(stringtonumoccurrencess.ContainsKey(str))
StringTonumEvents[str]++;
其他的
StringTonumEvents[str]=1;
}
返回StringTonumEvents;
这是一个foreach版本,就像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;
}
静态字典CountOrderedSequence(IEnumerable源代码)
{
var result=newdictionary();
字符串prev=null;
整数计数=0;
foreach(源中的var s)
{
如果(上一个!=s&&count>0)
{
结果。添加(上一个,计数);
计数=0;
}
prev=s;
++计数;
}
如果(计数>0)
{
结果。添加(上一个,计数);
}
返回结果;
}
更新了以添加对空源代码的必要检查-我仍然认为它比Jon的更简单:-)不,这不是家庭作业,我得到了一个编译时错误,出现上述错误:错误CS1660:无法将lambda表达式转换为类型“System.Collections.Generic.IEqualityComparer”,因为它不是委托类型。错误CS1502:与“System.Collections.Generic.Dictionary.this[string]”匹配的最佳重载方法具有一些无效属性arguments@Michael:谢谢,修正了我的答案。我不知道谁会投票否决你。除了一个合理的输入错误之外,您确实有了第一个正确的解决方案(使用LINQ)。Jon,感谢您查看此内容。我自己也在想这件事。最理想的情况是,我希望一次通过col1就可以构建一个字典,并且出现次数可以在运行中增加。感谢您详细说明了涉及循环的解决方案。我确实意识到这是一种“冗长”的方式,但我希望能有一种快速、简单(且高效)的方式通过LINQ来实现,而我忽略了这种方式。@Michael:LINQ通常不会提供任何只在非常特定的情况下才起作用的内容(例如已经订购的收藏)。@Jon,事实上,我并不介意在LINQ解决方案中进行如此多的字典查找,但是其他临时集合,即使每个组只创建一次,看起来也不太受欢迎。我想我希望有某种自引用LINQ解决方案可以使用字典,因为它是内置的
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;
}