当密钥基于多个标识属性时,优化字典以进行比较

时间:2009-07-22 14:01:39

标签: c# performance dictionary

我有以下代码:

if (!this._masterAccountDefinitions.ContainsKey(
     outletName.ToLower(CultureInfo.CurrentCulture) + "/" +
     officeName.ToLower(CultureInfo.CurrentCulture))
   ) {
     //Add new item to list
}

基本上,字典由出口名称和办公室名称组合键入。这段代码将被广泛调用,它似乎只是做了一些相当苛刻的字符串转换。我正在寻找关于更有效地键入字典的建议而不是简单地连接字符串值。

2 个答案:

答案 0 :(得分:1)

你有证据证明这会导致问题吗?我不希望它会导致任何问题 - 我想不出任何真正想要帮助的东西,除非你想用一个名字键来获得一个由另一个名字键入的“子词典” - 但这会使代码变得更加丑陋,在大多数情况下我无法看到它提高性能。

答案 1 :(得分:1)

假设效率意味着性能 - 很难推测连接字符串作为密钥的方法的哪些变化会产生更好的性能 - 你必须首先了解瓶颈是什么。

但是,我想到的一个想法是创建一个单独的类来表示键并覆盖其Equals()GetHashCode()方法。他们将在Equals()中使用不区分大小写的比较来使用各个字段,并在GetHashCode()中对哈希码进行异或。

这可能有助于避免将字符串转换为小写的成本,并消除连接它们的需要。但是,它引入了使用自定义类来键入集合的成本,该类需要针对存储在字典中的每个项进行实例化。此外,散列算法可能不如散列串联字符串更优化(即引起更多冲突)。

我强烈建议您花一些时间来分析您的代码,以确定在转换为更复杂的替代方案之前,只是连接字符串在您的情况下效率不高。

这是一个非常粗略的原型:

public class AccountKey
{
   private readonly string m_OutletName;
   private readonly string m_OfficeName;

   public AccountKey( string outlet, string office )
   {
      m_OutletName = outlet;
      m_OfficeName = office;
   }

   public string OutletName { get { return m_OutletName; } }
   public string OfficeName { get { return m_OfficeName; } }

   public override bool Equals( object otherKey )
   { 
      AccountKey otherAccountKey = otherKey as AccountKey;      
      if( otherAccountKey == null )
         return false;

      // uses Compare( s1, s2, ignoreCase ) overload - which assumes current culture
      // alternative culture can be passed in as another parameter after ignore case
      // uses short-circuit and to avoid comparing both strings if one already differs
      // you could order these based on your domain knowledge more optimally - for
      // example if Offices vary more frequently than Outlet, make that compare first.
      return String.Compare( m_OutletName, otherAccountKey.OutletName, true ) == 0 &&
             String.Compare( m_OfficeName, otherAccountKey.OfficeName, true ) == 0;
   }

   public override int GetHasCode()
   {
      // this may not be optimal, but it's a starting point
      return OutletName.GetHashCode() ^ OfficeName.GetHashCode();
   }
}