C# 双键元组列表或字典
我有一组两个键对的字符串{(a1,b1),(a2,b2),(a3,b3),…}。在我的场景(a1,b1)==(b1,a1),所以(a1,b1)或(b1,a1)组合应该只作为我的集合的一部分 在C#应用程序中,我需要能够:C# 双键元组列表或字典,c#,dictionary,C#,Dictionary,我有一组两个键对的字符串{(a1,b1),(a2,b2),(a3,b3),…}。在我的场景(a1,b1)==(b1,a1),所以(a1,b1)或(b1,a1)组合应该只作为我的集合的一部分 在C#应用程序中,我需要能够: 添加这些(a,b)元组的新对 高效(即快速)检查(a1,b1)或(b1,a1)对是否已在我的表中 您将如何使用Dictionary[Tuple[K1,K2]]或其他工具实现这样的功能?如果使用字典,有没有办法告诉它考虑(K1,K2)与(K2,K1)相同,这样我就不必添加两个
- 添加这些(a,b)元组的新对
- 高效(即快速)检查(a1,b1)或(b1,a1)对是否已在我的表中
谢谢。这是家庭作业吗?这看起来像是一本书中的问题
键
,定义相等和哈希运算符及方法。(这意味着您应该定义方法Equals
、运算符=
、方法GetHashCode
,如果编译器需要,还可能定义其他方法。)HashSet
创建一个实现的自定义类(并确保正确重写
GetHashCode
)。然后你可以在一个散列集中使用它,两对可以自动“相等”。我会使用一个字典,其中键由一个函数生成,该函数接受两个字符串并生成如下散列:比较两个字符串,构建一个由“较小”字符串+分隔符+较大”字符串组成的特定字符串。这样一来,顺序就不重要了。还可以实现类似的“equals”运算符。创建一个存储类,公开Add(a,b)和类似函数。内部存储器可以是哈希集
,其中T是合适的字符串元组键。关于这个键和比较器,唯一重要的是使用对称的散列函数和相等函数,即(a,b)等于(b,a),因此散列函数(a,b)=散列函数(b,a)
如前所述,许多散列函数都具有此属性,例如散列值的总和和异或。我选择不使用xor,因为这意味着所有对等字符串对的哈希值都为零,如果可能存在对等字符串对,这可能会导致查找效率低下
下面的实现假定所有字符串均为非null,但没有错误检查
public class Storage
{
private HashSet<Key> set;
public Storage()
{
set = new HashSet<Key>(new Key.Comparer());
}
public void Add(string a, string b)
{
set.Add(new Key{A=a, B=b});
}
public bool Contains(string a, string b)
{
return set.Contains(new Key{A=a, B=b});
}
internal class Key
{
internal String A { get; set; }
internal String B { get; set; }
internal class Comparer : IEqualityComparer<Key>
{
public bool Equals(Key x, Key y)
{
return (x.A == y.A && x.B == y.B) || (x.A == y.B && x.B == y.A);
}
public int GetHashCode(Key k)
{
int aHash = k.A.GetHashCode();
int bHash = k.B.GetHashCode();
// Hash for (x,y) same as hash for (y,x)
if (aHash > bHash)
return bHash * 37 + aHash;
return aHash * 37 + bHash;
}
}
}
}
公共类存储
{
私有哈希集;
公共存储()
{
set=newhashset(newkey.Comparer());
}
公共无效添加(字符串a、字符串b)
{
Add(新键{A=A,B=B});
}
公共布尔包含(字符串a、字符串b)
{
包含(新键{A=A,B=B});
}
内部类密钥
{
内部字符串A{get;set;}
内部字符串B{get;set;}
内部类比较器:IEqualityComparer
{
公共布尔等于(键x,键y)
{
返回(x.A==y.A和x.B==y.B)| |(x.A==y.B和x.B==y.A);
}
public int GetHashCode(键k)
{
int-aHash=k.A.GetHashCode();
int bHash=k.B.GetHashCode();
//(x,y)的哈希值与(y,x)的哈希值相同
如果(aHash>bHash)
返回bHash*37+aHash;
返回aHash*37+bHash;
}
}
}
}
显然,我不能键入lt或gt字符,它们不会被转义,所以我用括号/括号替换了它们。您需要如何处理集合?例如,您希望如何查找值?@JonSkeet我只需要快速检查(a1,b1)和(b1,a1)是否已在集合中。我正在处理大量的这些事情,所以它需要很快。谢谢。不,不是作业问题。。。我只是想用一种不含糊的方式来解释。但是如果我重写Equals方法,这不会减慢在列表中找到项目的速度吗?这不是违背了快速访问的目的吗?谢谢。我们这里几乎不能谈论减速,因为您只需要一种方法来比较两个键。如果您不提供一种比较键的方法,它将不起作用。这将正确地“索引”项目吗?我试图阻止“扫描”,即对每个项目检查调用“等于”。@pbz:只要您有一个合理的哈希代码,就可以了。GetHashCode应该是什么样子?key1+key2或key2+key1?@pbz其实并不重要,只要
和
产生完全相同的哈希代码。一个简单的加法就行了,或者一个XOR…这可能是基本的,但我显然遗漏了一些东西。你能给我一个例子吗,一对(“abc”,“def”)的哈希值与一对(“def”,“abc”)的哈希值相同?谢谢。是的,使用String.Compare(str1,str2)是一个老习惯,它总是组合散列,比如“a*素数+b”。当组合散列代码以避免冲突时,这是通常的简单模式,但我现在想起来,在做这样的对称散列时,我实际上不确定这是否严格必要。这可能是因为它在a,b之间产生了不对称性,如果我只对散列求和的话,这是不存在的。也许有人可以在这里填写,已经很晚了……当aHash和bHash是散列时,为什么不简单地将它们异或在一起呢?这不好吗?如果一个人经常添加相等字符串的元组,那就不好了,因为所有这些元组都得到相同的散列(零)。