我使用字典错了,似乎太慢了

时间:2011-07-12 07:03:34

标签: c#

我使用过VS profilier并注意到大约40%的时间程序花费在下面的行中。 我正在使用title1color1,因为Visual Studio或Resharper建议这样做。下面的代码中是否存在任何性能问题?

Dictionary<Item, int> price_cache = new Dictionary<Item, int>();
....


string title1 = title;
string color1 = color;
if (price_cache.Keys.Any(item => item.Title == title && item.Color == color))
{
    price = price_cache[price_cache.Keys.First(item => item.Title == title11  && item.Color == color1)];

5 个答案:

答案 0 :(得分:7)

问题是你的Keys.Any方法遍历字典中的所有键以查找是否匹配。之后,您使用First方法再次执行相同的操作。

当你已经拥有密钥并希望快速获取值时,字典适用于操作。在这种情况下,它将计算您的密钥的哈希码(在您的情况下为Item)并使用它来“跳转”到存储项目的存储区。

首先,您需要制作自定义比较器,让Dictionary知道如何比较项目。

class TitleColorEqualityComparer : IEqualityComparer<Item>
{
     public bool Equals(Item a, Item b) 
     {
          // you might also check for nulls here
          return a.Title == b.Title && 
              a.Color == b.Color;
     }

     public int GetHashCode(Item obj)
     {
          // this should be as much unique as possible,
          // but not too complicated to calculate
          int hash = 17;
          hash = hash * 31 + obj.Title.GetHashCode();
          hash = hash * 31 + obj.Color.GetHashCode();
          return hash;
     }
}

然后,使用自定义比较器实例化您的字典:

Dictionary<Item, int> price_cache = 
    new Dictionary<Item, int>(new TitleColorEqualityComparer());

从现在开始,您可以简单地写一下:

Item some_item = GetSomeItem();
price_cache[some_item] = 5; // to quickly set or change a value

或者,搜索字典:

Item item = GetSomeItem();
int price = 0;
if (price_cache.TryGetValue(item, out price))
{
    // we got the price
}
else
{
    // there is no such key in the dictionary
}

<强> [编辑]

再次强调:从不迭代Keys属性以查找密钥。如果你这样做,你根本不需要Dictionary,你可以简单地使用一个列表并获得相同的效果(甚至性能稍好)。

答案 1 :(得分:1)

尝试使用IEqualityComparer,如本页示例代码所示:http://msdn.microsoft.com/en-us/library/ms132151.aspx并根据标题和颜色计算哈希码。

答案 2 :(得分:1)

正如耶稣拉莫斯建议的那样(当他说使用不同的数据结构时),你可以将键设为一个字符串,它是标题和颜色的串联,然后连接搜索字符串并寻找它。它应该更快。

所以一个键可能看起来像name1:FFFFFF(名称,冒号,然后是颜色的十六进制),那么你只需要以相同的方式格式化搜索字符串。

答案 3 :(得分:1)

将您的price_cache.Keys.Any()替换为price_cache.Keys.SingleOrDefault(),这样您就可以将结果存储在变量中,检查是否为空,如果没有,则您已经拥有搜索到的项目,而不是像在此处一样搜索它

答案 4 :(得分:1)

如果要快速访问哈希表,则需要实现GetHashCode和Equals功能:

public class Item 
{
.....
    public override int GetHashCode()
    {
        return (this.color.GetHashCode() + this.title.GetHashCode())/2;
    }

    public override bool Equals(object o)
    {
        if (this == o) return true;
        var item = o as Item;
        return (item != null) && (item.color == color) &&  (item.title== title) ;
    }

访问您的词典,如:

Item item = ...// create sample item
int price = 0;

price_cache.ContainsKey(item);
price_cache[item];
price_cache.TryGetValue(item, out price);