好的,这是多个双向版本:
using System; using System.Collections.Generic; using System.Text; class BiDictionary{ IDictionary > firstToSecond = new Dictionary >(); IDictionary > secondToFirst = new Dictionary >(); private static IList EmptyFirstList = new TFirst[0]; private static IList EmptySecondList = new TSecond[0]; public void Add(TFirst first, TSecond second) { IList firsts; IList seconds; if (!firstToSecond.TryGetValue(first, out seconds)) { seconds = new List (); firstToSecond[first] = seconds; } if (!secondToFirst.TryGetValue(second, out firsts)) { firsts = new List (); secondToFirst[second] = firsts; } seconds.Add(second); firsts.Add(first); } // Note potential ambiguity using indexers (e.g. mapping from int to int) // Hence the methods as well... public IList this[TFirst first] { get { return GetByFirst(first); } } public IList this[TSecond second] { get { return GetBySecond(second); } } public IList GetByFirst(TFirst first) { IList list; if (!firstToSecond.TryGetValue(first, out list)) { return EmptySecondList; } return new List (list); // Create a copy for sanity } public IList GetBySecond(TSecond second) { IList list; if (!secondToFirst.TryGetValue(second, out list)) { return EmptyFirstList; } return new List (list); // Create a copy for sanity } } class Test { static void Main() { BiDictionary greek = new BiDictionary (); greek.Add(1, "Alpha"); greek.Add(2, "Beta"); greek.Add(5, "Beta"); ShowEntries(greek, "Alpha"); ShowEntries(greek, "Beta"); ShowEntries(greek, "Gamma"); } static void ShowEntries(BiDictionary dict, string key) { IList values = dict[key]; StringBuilder builder = new StringBuilder(); foreach (int value in values) { if (builder.Length != 0) { builder.Append(", "); } builder.Append(value); } Console.WriteLine("{0}: [{1}]", key, builder); } }
正如其他人所说的那样,字典中没有从值到键的映射.
我刚刚注意到你想要从值到多个键映射 - 我将这个解决方案留给单值版本,但我会为多条目双向映射添加另一个答案.
这里采用的常规方法是使用两个字典 - 一个映射单向,另一个映射.将它们封装在一个单独的类中,并在您有重复的键或值时计算出您想要执行的操作(例如,抛出异常,覆盖现有条目或忽略新条目).就个人而言,我可能会抛出异常 - 这使得成功行为更容易定义.像这样的东西:
using System; using System.Collections.Generic; class BiDictionary{ IDictionary firstToSecond = new Dictionary (); IDictionary secondToFirst = new Dictionary (); public void Add(TFirst first, TSecond second) { if (firstToSecond.ContainsKey(first) || secondToFirst.ContainsKey(second)) { throw new ArgumentException("Duplicate first or second"); } firstToSecond.Add(first, second); secondToFirst.Add(second, first); } public bool TryGetByFirst(TFirst first, out TSecond second) { return firstToSecond.TryGetValue(first, out second); } public bool TryGetBySecond(TSecond second, out TFirst first) { return secondToFirst.TryGetValue(second, out first); } } class Test { static void Main() { BiDictionary greek = new BiDictionary (); greek.Add(1, "Alpha"); greek.Add(2, "Beta"); int x; greek.TryGetBySecond("Beta", out x); Console.WriteLine(x); } }
字典并不是真的意味着像这样工作,因为虽然键的唯一性得到保证,但值的唯一性却不是.所以,例如,如果你有
var greek = new Dictionary{ { 1, "Alpha" }, { 2, "Alpha" } };
你期望得到greek.WhatDoIPutHere("Alpha")
什么?
因此,你不能指望这样的东西被卷入框架.您需要自己的方法来实现自己的独特用途 - 您想要返回一个数组(或IEnumerable
)吗?如果有多个具有给定值的键,是否要抛出异常?如果没有怎么办?
就个人而言,我会选择一个可枚举的,如下:
IEnumerableKeysFromValue (this Dictionary dict, TValue val) { if (dict == null) { throw new ArgumentNullException("dict"); } return dict.Keys.Where(k => dict[k] == val); } var keys = greek.KeysFromValue("Beta"); int exceptionIfNotExactlyOne = greek.KeysFromValue("Beta").Single();
也许最简单的方法,没有Linq,可以循环对:
int betaKey; foreach (KeyValuePairpair in lookup) { if (pair.Value == value) { betaKey = pair.Key; // Found break; } } betaKey = -1; // Not found
如果你有Linq,它可以通过这种方式轻松完成:
int betaKey = greek.SingleOrDefault(x => x.Value == "Beta").Key;