我基本上是在寻找一种方法来使用c#中的二维类型键来访问哈希表值。
最终我可以做这样的事情
HashTable[1][false] = 5;
int a = HashTable[1][false];
//a = 5
这就是我一直在尝试的......没有用的
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();
答案 0 :(得分: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
}
现在,您可以创建和使用普通的HashTable,并将此包装器用作Key。
答案 1 :(得分:23)
如何使用具有某种元组结构的常规Dictionary作为键?
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...
}
}
答案 2 :(得分:18)
以防最近有人在这里,如一个评论者所描述的,如果在.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."
}
}
答案 3 :(得分:15)
我认为这可能更接近您所寻找的......
var data = new Dictionary<int, Dictionary<bool, int>>();
答案 4 :(得分:15)
现在可以使用新元组在C#7.0中执行此操作:
// Declare
var test = new Dictionary<(int, bool), int>();
// Add
test.Add((1, false), 5);
// Get
int a = test[(1, false)];
答案 5 :(得分: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;
}
}
}
答案 6 :(得分:4)
你需要一个正确实现gethashcode的dictonary的密钥类。 你可以扩展dictonary,让你以友好的方式访问它。
密钥对类
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);
}
}
延伸Dictonary&lt;&gt;
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;
}
}
}
你就像这样使用它
KeyPairDictonary<int, bool, string> dict =
new KeyPairDictonary<int, bool, string>();
dict[1, false] = "test";
string test = dict[1, false];
答案 7 :(得分:1)
我建议您创建一个公开bool和int属性的小型自定义类,并覆盖其GetHashCode和Equals方法,然后将其用作键。
答案 8 :(得分:1)
基本上,您需要使用嵌入式哈希表。如果你想到你的
问题,具有两个键的哈希表是具有两个独立的功能
根据定义,变量和f(x,y)
是二维的。
但是你想使用它就像它是一个哈希表,而不是嵌入的哈希。所以你需要做的是创建一个包装嵌入式哈希表思想的对象,并像单个哈希一样运行。
有几个障碍:
GetEnumerator()
方法。而且你需要你自己的Iterator,它将在2维中正确迭代。我已经包含了我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Forms;
namespace YourProjectNameHere
{
public class Hashtable2D
{
/// <summary>
/// This is a hashtable of hashtables
/// The X dim is the root key, and the y is the internal hashes key
/// </summary>
///
private Hashtable root = new Hashtable();
public bool overwriteDuplicates = false;
public bool alertOnDuplicates = true;
public void Add(object key_x, object key_y, object toStore)
{
if(root[key_x]!=null)//If key_x has already been entered
{
Hashtable tempHT = (Hashtable)root[key_x];//IF the hash table does not exist then focus will skip to the catch statement
if (tempHT[key_y] == null) tempHT.Add(key_y, toStore);
else handleDuplicate(tempHT, key_y, toStore);
}else{//Making a new hashtable
Hashtable tempHT = new Hashtable();
tempHT.Add(key_y, toStore);
root.Add(key_x, tempHT);
}
}
public void Remove(object key_x, object key_y)
{
try{
((Hashtable)root[key_x]).Remove(key_y);
}catch(Exception e){
MessageBox.Show("That item does not exist");
}
}
public void handleDuplicate (Hashtable tempHT, object key_y, object toStore)
{
if (alertOnDuplicates) MessageBox.Show("This Item already Exists in the collection");
if (overwriteDuplicates)
{
tempHT.Remove(key_y);
tempHT.Add(key_y,toStore);
}
}
public object getItem(object key_x, object key_y)
{
Hashtable tempHT = (Hashtable)root[key_x];
return tempHT[key_y];
}
public ClassEnumerator GetEnumerator()
{
return new ClassEnumerator(root);
}
public class ClassEnumerator : IEnumerator
{
private Hashtable ht;
private IEnumerator iEnumRoot;
private Hashtable innerHt;
private IEnumerator iEnumInner;
public ClassEnumerator(Hashtable _ht)
{
ht = _ht;
iEnumRoot = ht.GetEnumerator();
iEnumRoot.MoveNext();//THIS ASSUMES THAT THERE IS AT LEAST ONE ITEM
innerHt = (Hashtable)((DictionaryEntry)iEnumRoot.Current).Value;
iEnumInner = innerHt.GetEnumerator();
}
#region IEnumerator Members
public void Reset()
{
iEnumRoot = ht.GetEnumerator();
}
public object Current
{
get
{
return iEnumInner.Current;
}
}
public bool MoveNext()
{
if(!iEnumInner.MoveNext())
{
if (!iEnumRoot.MoveNext()) return false;
innerHt = (Hashtable)((DictionaryEntry)iEnumRoot.Current).Value;
iEnumInner = innerHt.GetEnumerator();
iEnumInner.MoveNext();
}
return true;
}
#endregion
}
}
}
答案 9 :(得分:0)
这是我嵌套的Dictionary实现:
public class TwoKeysDictionary<K1, K2, T>:
Dictionary<K1, Dictionary<K2, T>>
{
public T this[K1 key1, K2 key2]
{
get => base.ContainsKey(key1) && base[key1].ContainsKey(key2) ? base[key1][key2] : default;
set
{
if (ContainsKey(key1) && base[key1].ContainsKey(key2))
base[key1][key2] = value;
else
Add(key1, key2, value);
}
}
public void Add(K1 key1, K2 key2, T value)
{
if (ContainsKey(key1))
{
if (base[key1].ContainsKey(key2))
throw new Exception("Couple " + key1 + "/" + key2 + " already exists!");
base[key1].Add(key2, value);
}
else
Add(key1, new Dictionary<K2, T>() { { key2, value } });
}
public bool ContainsKey(K1 key1, K2 key2) => ContainsKey(key1) && base[key1].ContainsKey(key2);
}
答案 10 :(得分:0)
我认为现在最简单的方法是使用Tupple.Create和ValueTuple.Create:
> var k1 = Tuple.Create("test", int.MinValue, DateTime.MinValue, double.MinValue);
> var k2 = Tuple.Create("test", int.MinValue, DateTime.MinValue, double.MinValue);
> var dict = new Dictionary<object, object>();
> dict.Add(k1, "item");
> dict.Add(k2, "item");
An item with the same key has already been added....
> dict[k1] == dict[k2]
true
或使用新的c#7元组语法创建元组键:
var k = (item1: "value1", item2: 123);
答案 11 :(得分:0)
看,这段代码运行得很好:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Services = new Dictionary<object, Hashtable>();
this.Services.Add("array1", new Hashtable());
this.Services["array1"]["qwe"] = "123";
this.Services["array1"][22] = 223;
object zz = null;
zz = this.Services["array1"]["qwe"];
MessageBox.Show(zz.ToString()); // shows qwe
zz = this.Services["array1"][22];
MessageBox.Show(zz.ToString()); // shows 22
}
现在我们只需要一个包装器来避免手动执行此操作.Services.Add(“array1”,new Hashtable());
答案 12 :(得分:0)
快速而肮脏的方法是从两条信息中创建一个复合键,例如
IDictionary<string, int> values = new Dictionary<string, int>();
int i = ...;
bool b = ...;
string key = string.Concat(i, '\0', b);
values[key] = 555;
为了更好地封装这个,你可以包装字典:
public class MyDict
{
private readonly IDictionary<string, int> values = new Dictionary<string, int>();
public int this[int i, bool b]
{
get
{
string key = BuildKey(i, b);
return values[key];
}
set
{
string key = BuildKey(i, b);
values[key] = value;
}
}
private static string BuildKey(int i, bool b)
{
return string.Concat(i, '\0', b);
}
}
为了使其更加健壮,将复合密钥封装为一种类型,例如包含两个字段的类,确保正确覆盖Equals()和GetHashCode()方法。
答案 13 :(得分:0)
这是一个example,您可以使用普通的Hashtable而不是我使用的Hashtable。
答案 14 :(得分:0)
将二维密钥包装在单独的type
中,并将该类型用作密钥。另请考虑覆盖GetHashCode()
和Equals()
方法。最好使用Dictionary<>
代替HashTable
,因为显然你可以使用它。
答案 15 :(得分:0)
您可以使用Dictionary<KeyValuePair<int,bool>,int>
吗?
答案 16 :(得分:0)
您可以“双嵌套”哈希表 - 换句话说,您的主词典是Dictionary<int, Dictionary<bool, my_return_type>>
类型。
这实现了您在第一个代码段中使用双括号表示法的目标。
当然,管理方面有点棘手。每次添加条目时,都需要测试主字典是否包含主键字典,如果没有则添加新字典,然后将辅助键和值添加到内部字典中。