在C#中查找表的最有效方法是什么?

时间:2009-12-06 16:43:04

标签: c# performance lookup-tables

在C#中查找表的最有效方法是什么

我有一张查询表。有点像

0 "Thing 1"
1 "Thing 2"
2 "Reserved"
3 "Reserved"
4 "Reserved"
5 "Not a Thing"

因此,如果有人想要“Thing 1”或“Thing 2”,他们会传递0或1.但是他们也可以传递其他东西。 我有256种这类东西,其中有200种是保留的。

那么最有效的想法是什么呢?

  • 字符串获取所有值的数组或字典变量。然后取整数并返回该位置的值。

我对此解决方案的一个问题是所有“保留”值。我不想创建那些冗余的“保留”值。或者我可以对所有“保留”的所有地方都有一个if语句,但它们现在可能只有2-3,可能是2-3,40-55以及字节中的所有不同位置。这个if语句会变得非常快速

  • 我想的另一个选择是switch语句。而且我将获得所有50个已知值并且将通过默认值保留值。

我想知道这是否比创建字符串数组或字典要多得多,只返回适当的值。

  • 别的什么?还有另一种方法可以考虑吗?

9 个答案:

答案 0 :(得分:13)

"Retrieving a value by using its key is very fast, close to O(1), because the Dictionary(TKey, TValue) class is implemented as a hash table."

var things = new Dictionary<int, string>();
things[0]="Thing 1";
things[1]="Thing 2";
things[4711]="Carmen Sandiego";

答案 1 :(得分:4)

在C#中查找整数值的绝对最快方法是使用数组。如果您尝试一次进行数万次查找,这可能比使用字典更可取。在大多数情况下,这是过度的;您需要优化开发人员的时间而不是处理器时间。

如果保留密钥不仅仅是查找表中没有的所有密钥(即,如果查找密钥可以返回找到的值,未找到状态或保留状态),则需要在某处保存保留的密钥。将它们保存为具有魔术值的字典条目(例如保留值为null的任何字典条目的键)是正常的,除非您编写的代码迭代字典的条目而不过滤它们。

解决该问题的一种方法是使用单独的HashSet<int>来存储保留的密钥,并将整个事物烘焙到类中,例如:

public class LookupTable
{
   public readonly Dictionary<int, string> Table { get; }
   public readonly HashSet<int> ReservedKeys { get; }

   public LookupTable()
   {
      Table = new Dictionary<int, string>();
      ReservedKeys = new HashSet<int>();
   }

   public string Lookup(int key)
   {
      return (ReservedKeys.Contains(key))
         ? null
         : Table[key];
   }
}

你会注意到这仍然存在魔术值问题 - 如果密钥是保留的,Lookup将返回null,如果不在表中,则抛出异常 - 但至少现在你可以迭代{ {1}}没有过滤魔术值。

答案 2 :(得分:3)

如果您有许多保留(当前未使用)值或者整数值的范围可能变得非常大,那么我会使用通用字典(Dictionary):

var myDictionary = new Dictionary<int, string>();
myDictionary.Add(0, "Value 1");
myDictionary.Add(200, "Another value");
// and so on

否则,如果您有一定数量的值且当前只有少数几个未使用,那么我将使用一个字符串数组(字符串[200])并将保留的条目设置/保留为空。

var myArray = new string[200];
myArray[0] = "Value 1";
myArray[2] = "Another value";
//myArray[1] is null

答案 3 :(得分:2)

查看HybridDictionary。它会根据大小自动调整其底层存储机制,以获得最大效率。

http://msdn.microsoft.com/en-us/library/system.collections.specialized.hybriddictionary.aspx

答案 4 :(得分:0)

内置Dictionary对象(最好是通用字典)对此非常理想,专门用于快速/高效地检索与键相关的值。

来自链接的MSDN文章:

  

使用其键检索值是   非常快,接近O(1),因为   字典&lt;(Of&lt;(TKey,TValue&gt;)&gt;)   class被实现为哈希表。

就你的“保留”键而言,如果我们只讨论几百个键/值,我根本不会担心。只有当你达到数十,甚至数十万个“保留”键/值时,你才能实现更有效的效果。

在这些情况下,最有效的存储容器可能是Sparse Matrix的实现。

答案 5 :(得分:0)

我不太确定我是否理解你的问题。你有一组字符串。每个字符串都与索引相关联。消费者请求提供索引并返回相应的字符串,除非索引是保留。正确?

你不能简单地在数组中将保留项设置为null。

如果没有,使用不包含保留项的字典似乎是一种合理的解决方案。

无论如何,如果你澄清问题,你可能会得到更好的答案。

答案 6 :(得分:0)

将所有值加载到

var dic = new Dictionary<int, string>();

并将其用于检索:

string GetDescription(int val)
{
     if(0 <= val && val < 256)
        if(!dic.Contains(val))
           return "Reserved";
        return dic[val];
    throw new ApplicationException("Value must be between 0 and 255");
}

答案 7 :(得分:0)

我会使用Dictionary来进行查找。到目前为止,这是最有效的查找方式。使用字符串将在O(n)区域的某处运行以找到对象。

如果需要的话,让第二个字典对你所有人进行反向查找可能是有用的

答案 8 :(得分:0)

您的问题似乎暗示查询键是一个整数。由于您最多有256个项目,因此查询键的范围为0..255,对吗?如果是这样,只需要一个256字符串的字符串数组,并使用该键作为数组的索引。

如果您的查询键是字符串值,那么它更像是一个真正的查找表。使用Dictionary对象很简单,但是如果你的原始速度只有50个左右的实际答案,那么自己动手的方法,比如二元搜索或trie,可能会更快。如果您使用二进制搜索,由于项目数量太少,您可以将其展开。

项目列表多久更改一次?如果它只是很少变化,你可以通过生成代码进行搜索来获得更好的速度,然后你可以编译并执行每个查询。

另一方面,我假设您已通过分析或taking stackshots证明此查找是您的瓶颈。如果在此查询中花费的时间少于10%,则是您的瓶颈,因此您可以做最容易编码的事情。