我对词典有疑问,希望你能帮助我。
我有以下声明:
class MainCollection<TKey1, TKey2, TValue> : Dictionary<KeyValuePair<TKey1, TKey2>, TValue>
问题是我无法通过TKey1 OR TKey2从这本词典中获取一个元素。 有没有办法只通过TKey1或TKey2获得一个元素,而不是TKey1和TKey2?
我写了以下代码:
public TValue GetItemByKey1(TKey1 key)
{
MainCollection<int, int, string> Coll = new MainCollection<int, int, string>();
var value = from s in Coll where s.Key.Key == key select s.Value;
}
但它已经有两个问题:
我该如何解决这些错误?我在这里找不到任何相关的问题。 提前谢谢!
答案 0 :(得分:5)
好的,您希望能够按TKey1
或TKey2
进行查找。然后你想要的是三个词典,每个键一个,然后一个用于键对。
class Foo<TFirstKey, TSecondKey, TValue> {
private readonly Dictionary<TFirstKey, List<TValue>> firstDictionary
= new Dictionary<TFirstKey, List<TValue>>();
private readonly Dictionary<TSecondKey, List<TValue>> secondDictionary
= new Dictionary<TSecondKey, List<TValue>>();
private Dictionary<Tuple<TFirstKey, TSecondKey>, TValue> dictionary
= new Dictionary<Tuple<TFirstKey, TSecondKey>, TValue>();
public IEnumerable<TValue> GetByFirstKey(TFirstKey firstKey) {
return this.firstDictionary[firstKey];
}
public IEnumerable<TValue> GetBySecondKey(TSecondKey secondKey) {
return this.secondDictionary[secondKey];
}
public TValue GetByKey(TFirstKey firstKey, TSecondKey secondKey) {
return this.dictionary[Tuple.Create(firstKey, secondKey)];
}
public void Add(TFirstKey firstKey, TSecondKey secondKey, TValue value) {
this.dictionary.Add(Tuple.Create(firstKey, secondKey), value);
if(this.firstDictionary.Keys.Contains(firstKey)) {
this.firstDictionary[firstKey].Add(value);
}
else {
this.firstDictionary.Add(firstKey, new List<TValue> { value });
}
if(this.secondDictionary.Keys.Contains(secondKey)) {
this.secondDictionary[secondKey].Add(value);
}
else {
this.secondDictionary.Add(secondKey, new List<TValue> { value });
}
}
}
请注意,只有(TFirstKey, TSecondKey)
的查找才是唯一的,因此您需要GetByFirstKey
和GetBySecondKey
来返回集合。
我会把剩下的细节留给你。
关键在于,如果要在任一键上快速查找,则需要两个字典(一个用于密钥对的每个坐标)。使用一个可以通过查询键集来工作,但这很慢(搜索键是线性的)。
答案 1 :(得分:1)
只需向集合本身添加一个方法:
public TValue GetItemByKey1(TKey1 key)
{
var value = from s in this.Keys where s.Key.Key == key select this[s];
return value.SingleOrDefault();
}
TKey2
可以使用类似的方法。
请注意,这些查找将比标准字典键查找慢 ,因为您正在迭代密钥集合,而不是利用字典本可以使用的哈希表。
答案 2 :(得分:1)
我建议不要使用KeyValuePair<TKey, TValue>
,因为KVP是一个结构,并且作为字典中的一个键表示该对象将存在一段时间。我建议改为Tuple<T1, T2>
。好处是Tuple是一种参考类型,您可以自由传递而无需复制。此外,Tuple是一个只读对象,就像KVPair一样。这是我写它的方式:
class Program
{
static void Main(string[] args)
{
MainCollection<int, string, DateTime> collection = new MainCollection<int, string, DateTime>();
collection.Add(Tuple<int, string>.Create(1, "Bob"), new DateTime(1992, 12, 1));
collection.Add(Tuple<int, string>.Create(2, "James"), new DateTime(1945, 9, 1));
collection.Add(Tuple<int, string>.Create(3, "Julie"), new DateTime(1976, 7, 15));
DateTime date;
date = collection.GetValue(1);
Console.WriteLine("Bob birthdate: {0}", date);
date = collection.GetValue("Julie");
Console.WriteLine("#3 birthdate: {0}", date);
Console.ReadLine();
}
}
public class MainCollection<TKey1, TKey2, TValue>
{
Tuple<TKey1, TKey2> key;
Dictionary<Tuple<TKey1, TKey2>, TValue> mainCollection = new Dictionary<Tuple<TKey1, TKey2>, TValue>();
public void Add(Tuple<TKey1, TKey2> Key, TValue Value)
{
mainCollection.Add(Key, Value);
}
public TValue GetValue(TKey1 Key)
{
return mainCollection.Where(k => k.Key.Item1.Equals(Key))
.Select(v => v.Value)
.FirstOrDefault();
}
public TValue GetValue(TKey2 Key)
{
return mainCollection.Where(k => k.Key.Item2.Equals(Key))
.Select(v => v.Value)
.FirstOrDefault();
}
}
public class Tuple<T1, T2>
{
readonly T1 item1;
readonly T2 item2;
Tuple(T1 item1, T2 item2)
{
this.item1 = item1;
this.item2 = item2;
}
public static Tuple<T1, T2> Create(T1 Item1, T2 Item2)
{
return new Tuple<T1, T2>(Item1, Item2);
}
public T1 Item1
{ get { return item1; } }
public T2 Item2
{ get { return item2; } }
}
}
注意:如果您不使用.Net 4.0
,我会包含一个Tuple实现 <强>更新强>:
将MainCollection
对象转换为使用多个词典将如下所示:
public class MainCollection<TKey1, TKey2, TValue>
{
Tuple<TKey1, TKey2> key;
Dictionary<TKey1, Tuple<TKey1, TKey2>> k1Dictionary = new Dictionary<TKey1, Tuple<TKey1, TKey2>>();
Dictionary<TKey2, Tuple<TKey1, TKey2>> k2Dictionary = new Dictionary<TKey2, Tuple<TKey1, TKey2>>();
Dictionary<Tuple<TKey1, TKey2>, TValue> mainCollection = new Dictionary<Tuple<TKey1, TKey2>, TValue>();
public void Add(Tuple<TKey1, TKey2> Key, TValue Value)
{
mainCollection.Add(Key, Value);
k1Dictionary.Add(Key.Item1, Key);
k2Dictionary.Add(Key.Item2, Key);
}
public TValue GetValue(TKey1 Key)
{
return mainCollection[k1Dictionary[Key]];
}
public TValue GetValue(TKey2 Key)
{
return mainCollection[k2Dictionary[Key]];
}
}