C#中使用MultiDimensional键的Hashtable

Sco*_*ess 62 c# dictionary hashtable

我基本上是在寻找一种方法来使用c#中的二维类型键来访问哈希表值.

最终我可以做这样的事情

HashTable[1][false] = 5;
int a = HashTable[1][false];
//a = 5
Run Code Online (Sandbox Code Playgroud)

这就是我一直在尝试的......没有用

Hashtable test = new Hashtable();
test.Add(new Dictionary<int, bool>() { { 1, true } }, 555);
Dictionary<int, bool> temp = new Dictionary<int, bool>() {{1, true}};
string testz = test[temp].ToString(); 
Run Code Online (Sandbox Code Playgroud)

Jar*_*Par 68

我认为更好的方法是将多维键的许多字段封装到类/结构中.例如

struct Key {
  public readonly int Dimension1;
  public readonly bool Dimension2;
  public Key(int p1, bool p2) {
    Dimension1 = p1;
    Dimension2 = p2;
  }
  // Equals and GetHashCode ommitted
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以创建和使用普通的HashTable,并将此包装器用作Key.

  • 不要忘记你需要覆盖GetHashCode和Equals以在Hashtable中使用它. (10认同)
  • @David,不是这种情况.Equals的默认实现只对在这种情况下工作的所有字段执行相等.GetHashcode可能不如用户所希望的那样高效,但它也可以使用默认实现. (7认同)
  • @David,据说,实际上这通常是一种好习惯. (6认同)
  • @JaredPar这样做是值得的.我们最近发现了`struct`类型的`GetHashCode`的默认实现的性能问题.手动实现完全消除了这个瓶颈.此外,虽然是一个不同的解决方案,但我们发现"字典中的字典"方法在所有常见操作(`Dictionary <int,Dictionary <string,object >>`)上运行得更快.但是,这不允许复合键的空部分,而上面的`struct` /`class`键可以很容易地允许空值而不需要任何额外的工作. (5认同)

小智 23

如何使用具有某种元组结构的常规字典作为键?

public class TwoKeyDictionary<K1,K2,V>
{
    private readonly Dictionary<Pair<K1,K2>, V> _dict;

    public V this[K1 k1, K2 k2]
    {
        get { return _dict[new Pair(k1,k2)]; }
    }

    private struct Pair
    {
        public K1 First;
        public K2 Second;

        public override Int32 GetHashCode()
        {
            return First.GetHashCode() ^ Second.GetHashCode();
        }

        // ... Equals, ctor, etc...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Mugen Tuples在09年不在身边. (15认同)
  • 您不必实现Pair,使用System.Tuple (9认同)

Hüs*_*ğlı 21

您现在可以使用新元组在C#7.0中执行此操作:

// Declare
var test = new Dictionary<(int, bool), int>();

// Add
test.Add((1, false), 5);

// Get
int a = test[(1, false)];
Run Code Online (Sandbox Code Playgroud)

  • 注意:要在较旧的 .NET 目标框架上使用它,需要一个 [额外的 nuget 包](/sf/answers/2686814511/)。 (2认同)

Par*_*Joe 19

以防万一有人最近在这里,如一个评论者所描述的,如何在.Net 4.0中快速而肮脏的方式这样做的例子.

class Program
{
  static void Main(string[] args)
  {
     var twoDic = new Dictionary<Tuple<int, bool>, String>();
     twoDic.Add(new Tuple<int, bool>(3, true), "3 and true." );
     twoDic.Add(new Tuple<int, bool>(4, true), "4 and true." );
     twoDic.Add(new Tuple<int, bool>(3, false), "3 and false.");

     // Will throw exception. Item with the same key already exists.
     // twoDic.Add(new Tuple<int, bool>(3, true), "3 and true." );

     Console.WriteLine(twoDic[new Tuple<int, bool>(3,false)]);
     Console.WriteLine(twoDic[new Tuple<int, bool>(4,true)]);
     // Outputs "3 and false." and "4 and true."
  }
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*yon 16

我想这可能更接近你正在寻找的东西......

var data = new Dictionary<int, Dictionary<bool, int>>();
Run Code Online (Sandbox Code Playgroud)


And*_*asN 5

Dictonary您需要一个正确实现的关键类GetHashCode。并且您可以扩展Dictonary以让您以友好的方式访问它。

班上KeyPair

public class KeyPair<Tkey1, Tkey2>
{
    public KeyPair(Tkey1 key1, Tkey2 key2)
    {
        Key1 = key1;
        Key2 = key2;
    }

    public Tkey1 Key1 { get; set; }
    public Tkey2 Key2 { get; set; }

    public override int GetHashCode()
    {
        return Key1.GetHashCode() ^ Key2.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        KeyPair<Tkey1, Tkey2> o = obj as KeyPair<Tkey1, Tkey2>;
        if (o == null)
            return false;
        else
            return Key1.Equals(o.Key1) && Key2.Equals(o.Key2);
    }
}
Run Code Online (Sandbox Code Playgroud)

延长Dictonary<>

public class KeyPairDictonary<Tkey1, Tkey2, Tvalue> 
    : Dictionary<KeyPair<Tkey1, Tkey2>, Tvalue>
{
    public Tvalue this[Tkey1 key1, Tkey2 key2]
    {
        get
        {
            return this[new KeyPair<Tkey1, Tkey2>(key1, key2)];
        }
        set
        {
            this[new KeyPair<Tkey1, Tkey2>(key1, key2)] = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以这样使用它:

KeyPairDictonary<int, bool, string> dict = 
    new KeyPairDictonary<int, bool, string>();

dict[1, false] = "test";
string test = dict[1, false];
Run Code Online (Sandbox Code Playgroud)


小智 5

我建议jachymko的解决方案略有不同,这将允许您避免为密钥对创建一个类.而是包装一个字典的私人字典,如下所示:

public class MultiDictionary<K1, K2, V>
{
    private Dictionary<K1, Dictionary<K2, V>> dict = 
        new Dictionary<K1, Dictionary<K2, V>>();

    public V this[K1 key1, K2 key2]
    {
        get
        {
            return dict[key1][key2];
        }

        set
        {
            if (!dict.ContainsKey(key1))
            {
                dict[key1] = new Dictionary<K2, V>();
            }
            dict[key1][key2] = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不是出于任何效率原因,而是因为我认为代码更简单(看看你必须忽略的).如果效率是主要关注点,那么我同意您的原始解决方案更好.我不喜欢像Pair <T,U>这样的类型,特别是当.NET 4.0将包含开箱即用的元组时. (4认同)
  • 为什么?我考虑了这一秒,但在我看来更糟糕,因为它有更大的开销(更多的GC压力,更糟糕的局部性)并且它没有任何好处 - 在哈希表中搜索具有平均恒定的时间效率,所以没有这样做了两次. (3认同)
  • @jachymko如果效率被定义为速度而不是内存使用,那么使用更简单类型的字典解决方案中的直字典实际上会更快地执行.使用`struct`或其他类型创建的复合键导致性能下降,原因我尚未确定. (2认同)