我是C#的新手,需要有一个包含多个键的通用列表。
我有三个参数来创建我的数据的密钥。对于每条记录(每三个键),我有一组值。
我需要一个通用列表,列表中每个节点的值都是我的键值,每个节点的值指向包含该键相关值的列表。
以下是我正在寻找的数据和数据结构示例:
Key1 Key2 Key3 Value1 Value2 Value3
0 0 0 a b c
0 0 1 d e f
0 1 1 g h -
<0,0,0, List(a,b,c)> ---> <0,0,1,list(d,e,f)>---> <0,1,1,List(g,h)>--->Null
我在考虑使用包含多个键的哈希表以及指向作为链接列表的对象的值。 或者使用这三个键创建一个字典,然后再次返回指向链接列表头部的指针。
如果有人能告诉我如何在C#中做到这一点,我将不胜感激。
答案 0 :(得分:1)
首先,您绝对应该使用Dictionary<TKey, TValue>
,而不是HashTable
。非泛型集合类型实际上只是为了向后兼容。最好将通用类型用于新代码。
至于您的具体问题,您会注意到.NET字典类型只允许一个键。实际上,这通常是字典集合的典型。集合中的每个条目都是一个键/值对。
但是,您可以将三个键值组合到一个对象值中,并将其用作键。实际上,.NET提供了各种Tuple
类来实现这一点,每个类型参数计数都有一个不同的类,因此对于对象中的每个项目计数。此外,这些类都实现了适当的比较和散列,以用作字典键。
现在,将此问题应用于您的问题,您可以选择一些选项,具体取决于您真正想要做的事情。不幸的是,你不清楚自己想做什么。 :(
如果每个键值的三元组最多只能有三个值,那么我认为评论者Mephy的建议很好。您可以声明您的集合并将其初始化为:
Dictionary<Tuple<int, int, int>, Tuple<string, string, string>> collection =
new Dictionary<Tuple<int, int, int>, Tuple<string, string, string>>
{
{ Tuple.Create(0, 0, 0), Tuple.Create("a", "b", "c") },
{ Tuple.Create(0, 0, 1), Tuple.Create("d", "e", "f") },
{ Tuple.Create(0, 1, 1), Tuple.Create("g", "h", null) },
};
请注意,null
用于表示字典值元组中的缺失值。
但是,如果你真的想要一个列表对象作为值,你可以改为做这样的事情:
Dictionary<Tuple<int, int, int>, List<string>> collection =
new Dictionary<Tuple<int, int, int>, List<string>>
{
{ Tuple.Create(0, 0, 0), new List<string> { "a", "b", "c"} },
{ Tuple.Create(0, 0, 0), new List<string> { "d", "e", "f"} },
{ Tuple.Create(0, 0, 0), new List<string> { "g", "h" } },
};
至于将上述视为键/值对的列表,与任何.NET集合类型一样,Dictionary<TKey, TValue>
可以视为值的枚举,在这种情况下,通过IEnumerable<KeyValuePair<TKey, TValue>>
的实现其中TKey
和TValue
与字典对象本身使用的类型相同。所以你可以这样做:
foreach (KeyValuePair<Tuple<int, int, int>, List<string>> kvp in collection)
{
// here, kvp.Key will have the Tuple<int, int, int> key value
// for the dictionary entry, while kvp.Value will have the
// List<string> value for the same entry.
}
请注意,.NET中字典类型的枚举顺序是未定义的。您没有得到任何保证,将以任何特定顺序退回元素,例如按照添加顺序排列。如果你需要一个特定的订单,你必须以某种方式强加给你。
最后,请注意上面示例中的KeyValuePair<TKey, TValue>
类型。这实际上只是一个元组的特例(尽管它早于.NET中的实际Tuple...
类)。即它是专门为存储键/值对而设计的自定义类。
如果您愿意,您可以自己声明这样一种类型作为词典的关键词。这样做的好处是允许您为类型提供特定的,可读的名称,当然也可以避免处理Tuple...
类所涉及的一些冗长(Tuple.Create()
泛型方法有帮助,但声明仍然可能变得难以处理)。这样做当然是以编写自己的比较和哈希码为代价的。
您可以通过创建一个继承您需要的Tuple...
类的类来找到中间立场,在该类中只实现构造函数(将初始化参数传递给基础构造函数),例如:
class CustomKey : Tuple<int, int, int>
{
public CustomKey(int i1, int i2, int i3) : base(i1, i2, i3) { }
}
或简单地使用Tuple...
指令使模块中的using
类型别名,为Tuple...
类型提供更具可读性的本地可用名称,例如:
using CustomKey = System.Tuple<int, int, int>;
前者使您可以轻松访问项目中任何位置的可读名称,但需要实现(非常短的)类;后者需要的工作量较少,但仅适用于单个源文件。