如何计算Dictionary中唯一值的出现次数?

我有一个字典,双精度值和字符串作为键。

我想计算这个字典中每个值的出现次数,我想知道这个值(例如重复)。

例如:

key1, 2 key2, 2 key3, 3 key4, 2 key5, 5 key6, 5 

我想得到一个清单:

 2 - 3 (times) 3 - 1 (once) 5 - 2 (twice) 

我该怎么做?

首先要注意的是,你实际上并不关心字典的键。 因此,第一步是忽略它们与手头的任务无关。 我们将使用字典的Values属性,并且工作与任何其他整数集合(或者我们可以比较的任何其他类型的任何其他类型的可枚举)相同。

这个问题有两种常见的方法,这两种方法都值得了解。

第一个使用另一个字典来保存值的数量:

 //Start with setting up the dictionary you described. Dictionary dict = new Dictionary{ {"key1", 2}, {"key2", 2}, {"key3", 3}, {"key4", 2}, {"key5", 5}, {"key6", 5} }; //Create a different dictionary to store the counts. Dictionary valCount = new Dictionary(); //Iterate through the values, setting count to 1 or incrementing current count. foreach(int i in dict.Values) if(valCount.ContainsKey(i)) valCount[i]++; else valCount[i] = 1; //Finally some code to output this and prove it worked: foreach(KeyValuePair kvp in valCount)//note - not sorted, that must be added if needed Console.WriteLine("{0} - {1}", kvp.Key, kvp.Value); 

希望这非常简单。 另一种方法更复杂但有一些优点:

 //Start with setting up the dictionary you described. Dictionary dict = new Dictionary{ {"key1", 2}, {"key2", 2}, {"key3", 3}, {"key4", 2}, {"key5", 5}, {"key6", 5} }; IEnumerable> grp = dict.Values.GroupBy(x => x); //Two options now. One is to use the results directly such as with the //equivalent code to output this and prove it worked: foreach(IGrouping item in grp)//note - not sorted, that must be added if needed Console.WriteLine("{0} - {1}", item.Key, item.Count()); //Alternatively, we can put these results into another collection for later use: Dictionary valCount = grp.ToDictionary(g => g.Key, g => g.Count()); //Finally some code to output this and prove it worked: foreach(KeyValuePair kvp in valCount)//note - not sorted, that must be added if needed Console.WriteLine("{0} - {1}", kvp.Key, kvp.Value); 

(我们可能使用var而不是详细的IEnumerable> ,但在解释代码时值得精确)。

直接比较,这个版本较差 – 理解起来更复杂,效率更低。 但是,学习这种方法可以实现相同技术的一些简洁有效的变体,因此值得研究。

GroupBy()接受枚举并创建另一个包含键值对的枚举,其中值也是枚举。 lambda x => x意味着它所分组的内容本身,但我们对不同的分组规则具有灵活性。 grp的内容看起来有点像:

 { {Key=2, {2, 2, 2}} {Key=3, {3}} {Key=5, {5, 5}} } 

所以,如果我们为每个组循环遍历这个,我们拉出Key并在组上调用Count() ,我们得到我们想要的结果。

现在,在第一种情况下,我们在单个O(n)传递中构建我们的计数,而在这里我们在O(n)传递中构建组,然后在第二次O(n)传递中获得计数,效率低得多。 这也有点难以理解,为什么还要提呢呢?

嗯,首先是一旦我们理解了它,我们可以改变界限:

 IEnumerable> grp = dict.Values.GroupBy(x => x); foreach(IGrouping item in grp) Console.WriteLine("{0} - {1}", item.Key, item.Count()); 

成:

 foreach(var item in dict.Values.GroupBy(x => x)) Console.WriteLine("{0} - {1}", item.Key, item.Count()); 

这是非常简洁的,并且变得惯用。 如果我们希望继续使用值计数对执行更复杂的操作,那将是特别好的,因为我们可以将其链接到另一个操作。

将结果放入字典的版本可以更简洁:

 var valCount = dict.Values.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()); 

在那里,您的整个问题在一个简短的行中回答,而不是第一个版本的6个(删除注释)。

(有些人可能更喜欢用dict.GroupBy(x => x.Value)替换dict.Values.GroupBy(x => x) ,一旦我们运行Count()就会得到完全相同的结果。如果你不是’立即确定原因,尝试解决问题)。

另一个优点是,在其他情况下,我们可以更灵活地使用GroupBy 。 由于这些原因,习惯使用GroupBy人很可能从dict.Values.GroupBy(x => x).ToDictinary(g => g.Key, g => g.Count());的一行简洁开始dict.Values.GroupBy(x => x).ToDictinary(g => g.Key, g => g.Count()); 如果它被certificate是一个性能热点,那么改为第一个版本的更详细但更有效的forms(我们在新词典中增加运行总数)。

更简单的是:

 Private Function CountOccurenceOfValue(dictionary As Dictionary(Of Integer, Integer), valueToFind As Integer) As Integer Return (From temp In dictionary Where temp.Value.Equals(valueToFind) Select temp).Count() End Function 

(是的,它在VB.NET中,但你不应该有很多麻烦转换为C#:-))