性能字典<string,int>与List <string>

时间:2016-01-22 18:52:04

标签: c# performance collections

我有一个大约500个字符串的列表“joe”“john”“jack”...“jan”

我只需要找到序数。

在我的例子中,列表永远不会改变。

可以将它们放在列表和IndexOf

ll.Add("joe")
ll.Add("john")
...
ll.Add("jan")
ll.IndexOf("jib") is 315

或者你可以使用序数整数作为值将它们放在字典中,

dd.Add("joe", 1)
dd.Add("john", 2)
dd.Add("jack", 3)
...
dd.Add("jan", 571)
dd["jib"] is 315

FTR字符串长度为3到8个字符。 FTR这是一个统一的,因此Mono,环境。

1)纯粹为了表现,一种方法通常更受欢迎?

1b实际上,我发现了许多这种性质的分析:http://www.dotnetperls.com/dictionary-time(google进行了大量类似的分析)。这适用于我描述的情况还是我在这里?

2)关于哪个在一般的开发工程意义上更好。 (完全抛开表现。)在我看来,两者都有明显的优点和缺点; 既不优雅

3)遗憾的是没有“HashSetLikeThingWithOrdinality”类型的设施 - 如果我错过了明显的请告诉我们。实际上,这似乎是一个相当普遍的,基本的集合用例 - “获得一些字符串的序数” - 也许我完全错过了一些明显的东西。

3 个答案:

答案 0 :(得分:5)

以下是使用Dictionary<string,int>和(已排序)List<string>之间差异的小概述:

观察: 1)在我的微基准测试中,一旦创建了字典,字典就会快得多。 (关于为什么会很快跟进的说明) 2)在我看来,以某种方式进行映射(例如,DictionaryHashTable)将不那么尴尬。

性能:

对于List<string>,要进行二分搜索,系统将从“中间”开始,然后走向每个方向(步入现在减半的搜索空间中的“中间”,在典型的鸿沟中征服模式)取决于该值是大于还是小于它正在查看的索引处的值。这是O(log n)增长。这假设数据已经以某种方式排序(也适用于SortedDictionary之类的东西,它使用允许二进制搜索的数据结构)

或者,您需要执行IndexOf,这是O(n)复杂度,因为您必须遍历每个元素。

对于Dictionary<string,int>,它使用哈希查找(通过调用.GetHashCode()上的TKey生成对象的哈希值(本例中为字符串),然后使用它查找在哈希表中(然后进行比较以确保它是精确匹配),并获得值。这大约是O(1)增长(即复杂性不会随着元素的数量而有意义地增长)[不包括涉及哈希冲突的最坏情况场景]

因此,Dictionary<string,int>需要(相对)恒定的时间来进行查找,而List<string>根据元素的数量增长(尽管是以对数(慢)速率)。 / p>

测试: 我做了一些微基准测试,在那里我获得了前500名的女性名字并对他们进行了查找。查找看起来像这样:

var searchItems = new[] { "Maci", "Daria", "Michelle", "Amber", "Henrietta"};

foreach (var item in searchItems)
{
    sortedList.BinarySearch(item); //You'd store the output here. Just looking at performance
}

并将其与字典查找进行比较:

 foreach (var item in searchItems)
 {
     var output = dictionary.ContainsKey(item) ? dictionary[item] : -1; //Presumably, output would be declared outside of this, just getting rid of a compiler error
 }

所以,这就是事情:即使对于少量的元素,使用短字符串作为查找键,排序的List<string>也不是更快(在我的机器上,在我公认的简单测试中)而不是{ {1}}。再一次,这是一个微基准测试,但对于500个元素,使用字典,5个查找速度大约快3倍。

但请注意,列表为6.3 微秒,字典为1.8 微秒

语法: 使用列表作为查找来查找索引有点尴尬。映射类型(如Dictionary<string,int>)意味着意图比查找列表更好,这最终会使代码更易于维护。

那就是说,根据我的语法和性能考虑因素,我会说与词典一起使用。但是,如果你因为某种原因不喜欢字典,那么性能考虑因素就会很小,无论如何都要担心它是无意义的。

编辑:奖励积分,您可能希望对任一方法使用不区分大小写的比较器。您可以将比较器作为Dictionary的参数传递,Dictionary也应支持比较器。

答案 1 :(得分:3)

我怀疑某处可能会出现扭曲,因为这样一个简单的问题在2小时内没有答案。我冒着被投票的风险,但这是我的答案:

1)字典(基于哈希表)显然是快速查找的更好选择。另一方面,列表是最糟糕的选择。

1.b)是的,它适用于此处。列表中的搜索具有线性复杂性,而词典提供恒定时间查找。

2)您正在尝试将字符串映射到序数;任何类型的地图都是自然的(虽然任何类型的列表都很尴尬)。

答案 2 :(得分:2)

字典是查找的自然方法。

列表将是以降低速度为代价减少内存使用的优化。数组会做得更好(同时,但内存会稍微减少)。

如果由于某些其他原因你已经有了一个列表或数组,那么内存节省会更大,因为不再使用将会使用的内存,因此以相同的速度优化空间以加快速度。 (如果键的顺序与排序相同则可以是O(log n),否则它是O(n))。

创建字典本身需要时间,所以虽然它是最快的方法,如果它被查找的次数很少,那么它可能会节省成本,因此不值得。