按值获取字典键
Posted
技术标签:
【中文标题】按值获取字典键【英文标题】:Get dictionary key by value 【发布时间】:2011-01-27 11:49:36 【问题描述】:如何在 C# 中?
Dictionary<string, string> types = new Dictionary<string, string>()
"1", "one",
"2", "two",
"3", "three"
;
我想要这样的东西:
getByValueKey(string value);
getByValueKey("one")
必须返回 "1"
。
最好的方法是什么?也许是 HashTable 或 SortedLists?
【问题讨论】:
我以前读过这篇文章,但回答到那里。 是的,但是你会得到an accepted answer from Skeet。 这里接受的答案比重复问题中的所有内容都要好得多。但是这个问题更老了。乔恩回答时可能不存在 lambda 表达式。 重新打开这个问题,因为另一个问题专门针对 .Net 2.0,而这个问题没有,并且对当前版本的 .Net 框架有更好的答案。 这能回答你的问题吗? Getting multiple keys of specified value of a generic Dictionary? 【参考方案1】:值不一定必须是唯一的,因此您必须进行查找。你可以这样做:
var myKey = types.FirstOrDefault(x => x.Value == "one").Key;
如果值是唯一的并且插入的频率低于读取的频率,则创建一个逆字典,其中值是键,键是值。
【讨论】:
@loviji:请记住,在循环解决方案中,如果该值恰好位于字典的末尾,则必须遍历所有其他值才能找到它。如果您有许多条目,这会减慢您的程序。 @Zach Johnson:谢谢。我同意你的看法。你的回答我也喜欢。但在我的字典中有 8-10 个条目。并且它们不是动态添加的。我认为,使用这个答案不错的解决方案。 我在这里遗漏了什么吗?上面的代码返回值,而不是键。 types.FirstOrDefault(x => x.Value == "one").Key 不是更合适吗? 警告所有人,如果 FirstOrDefault 找不到匹配项并尝试访问 null 对象上的“Key”,则接受的编辑将引发异常。 @JimYarbro:因为KeyValuePair<Tkey,Tvalue>
是一个结构,所以是一个值类型,它永远不可能是null
。 FirstOrDefault
将返回一个实例,其中所有字段都使用其默认值初始化(如 null
用于字符串或 0 用于整数)。所以你不会得到例外。但是你也不知道你是否找到了一个值,所以这个答案没有涵盖该值不存在的情况。【参考方案2】:
你可以这样做:
-
通过遍历字典中的所有
KeyValuePair<TKey, TValue>
(如果字典中有许多条目,这将对性能造成相当大的影响)
使用两个字典,一个用于值到键的映射,一个用于键到值的映射(这将占用两倍的内存空间)。
如果不考虑性能,请使用方法 1,如果不考虑内存,请使用方法 2。
此外,所有键都必须是唯一的,但值不需要是唯一的。您可能有多个具有指定值的键。
【讨论】:
为了以编程方式创建逆字典,我们仍然需要使用方法 1,对吧? 如果这种情况很常见,那么我也会推荐这种交换方式(关于你的最后一个问题)。【参考方案3】:我遇到了LINQ 绑定不可用并且必须显式扩展 lambda 的情况。它产生了一个简单的函数:
public static T KeyByValue<T, W>(this Dictionary<T, W> dict, W val)
T key = default;
foreach (KeyValuePair<T, W> pair in dict)
if (EqualityComparer<W>.Default.Equals(pair.Value, val))
key = pair.Key;
break;
return key;
这样称呼它:
public static void Main()
Dictionary<string, string> dict = new Dictionary<string, string>()
"1", "one",
"2", "two",
"3", "three"
;
string key = KeyByValue(dict, "two");
Console.WriteLine("Key: " + key);
它适用于 .NET 2.0 和其他受限环境。
【讨论】:
添加它作为扩展方法更好:-)【参考方案4】:public static string GetKeyFromValue(string valueVar)
foreach (string keyVar in dictionaryVar.Keys)
if (dictionaryVar[keyVar] == valueVar)
return keyVar;
return null;
其他人可能有更有效的答案,但我个人觉得这更直观,而且对我来说很有效。
【讨论】:
这些值可能不是唯一的。那会发生什么?它是否总是返回相同的密钥(例如,在新进程中)?【参考方案5】:我创建了一个双重查找类:
/// <summary>
/// dictionary with double key lookup
/// </summary>
/// <typeparam name="T1">primary key</typeparam>
/// <typeparam name="T2">secondary key</typeparam>
/// <typeparam name="TValue">value type</typeparam>
public class cDoubleKeyDictionary<T1, T2, TValue>
private struct Key2ValuePair
internal T2 key2;
internal TValue value;
private Dictionary<T1, Key2ValuePair> d1 = new Dictionary<T1, Key2ValuePair>();
private Dictionary<T2, T1> d2 = new Dictionary<T2, T1>();
/// <summary>
/// add item
/// not exacly like add, mote like Dictionary[] = overwriting existing values
/// </summary>
/// <param name="key1"></param>
/// <param name="key2"></param>
public void Add(T1 key1, T2 key2, TValue value)
lock (d1)
d1[key1] = new Key2ValuePair
key2 = key2,
value = value,
;
d2[key2] = key1;
/// <summary>
/// get key2 by key1
/// </summary>
/// <param name="key1"></param>
/// <param name="key2"></param>
/// <returns></returns>
public bool TryGetValue(T1 key1, out TValue value)
if (d1.TryGetValue(key1, out Key2ValuePair kvp))
value = kvp.value;
return true;
else
value = default;
return false;
/// <summary>
/// get key1 by key2
/// </summary>
/// <param name="key2"></param>
/// <param name="key1"></param>
/// <remarks>
/// 2x O(1) operation
/// </remarks>
/// <returns></returns>
public bool TryGetValue2(T2 key2, out TValue value)
if (d2.TryGetValue(key2, out T1 key1))
return TryGetValue(key1, out value);
else
value = default;
return false;
/// <summary>
/// get key1 by key2
/// </summary>
/// <param name="key2"></param>
/// <param name="key1"></param>
/// <remarks>
/// 2x O(1) operation
/// </remarks>
/// <returns></returns>
public bool TryGetKey1(T2 key2, out T1 key1)
return d2.TryGetValue(key2, out key1);
/// <summary>
/// get key1 by key2
/// </summary>
/// <param name="key2"></param>
/// <param name="key1"></param>
/// <remarks>
/// 2x O(1) operation
/// </remarks>
/// <returns></returns>
public bool TryGetKey2(T1 key1, out T2 key2)
if (d1.TryGetValue(key1, out Key2ValuePair kvp1))
key2 = kvp1.key2;
return true;
else
key2 = default;
return false;
/// <summary>
/// remove item by key 1
/// </summary>
/// <param name="key1"></param>
public void Remove(T1 key1)
lock (d1)
if (d1.TryGetValue(key1, out Key2ValuePair kvp))
d1.Remove(key1);
d2.Remove(kvp.key2);
/// <summary>
/// remove item by key 2
/// </summary>
/// <param name="key2"></param>
public void Remove2(T2 key2)
lock (d1)
if (d2.TryGetValue(key2, out T1 key1))
d1.Remove(key1);
d2.Remove(key2);
/// <summary>
/// clear all items
/// </summary>
public void Clear()
lock (d1)
d1.Clear();
d2.Clear();
/// <summary>
/// enumerator on key1, so we can replace Dictionary by cDoubleKeyDictionary
/// </summary>
/// <param name="key1"></param>
/// <returns></returns>
public TValue this[T1 key1]
get => d1[key1].value;
/// <summary>
/// enumerator on key1, so we can replace Dictionary by cDoubleKeyDictionary
/// </summary>
/// <param name="key1"></param>
/// <returns></returns>
public TValue this[T1 key1, T2 key2]
set
lock (d1)
d1[key1] = new Key2ValuePair
key2 = key2,
value = value,
;
d2[key2] = key1;
【讨论】:
【参考方案6】:可能是这样的:
foreach (var keyvaluepair in dict)
if(Object.ReferenceEquals(keyvaluepair.Value, searchedObject))
//dict.Remove(keyvaluepair.Key);
break;
【讨论】:
【参考方案7】:types.Values.ToList().IndexOf("one");
Values.ToList() 将您的字典值转换为对象列表。 IndexOf("one") 在新列表中搜索“one”并返回与字典中键/值对的索引匹配的索引。
此方法不关心字典键,它只是返回您要查找的值的索引。
请记住,您的字典中可能有多个“一”值。这就是没有“获取密钥”方法的原因。
【讨论】:
【参考方案8】:以下代码仅在包含唯一值数据时才有效:
public string getKey(string Value)
if (dictionary.ContainsValue(Value))
var ListValueData = new List<string>();
var ListKeyData = new List<string>();
var Values = dictionary.Values;
var Keys = dictionary.Keys;
foreach (var item in Values)
ListValueData.Add(item);
var ValueIndex = ListValueData.IndexOf(Value);
foreach (var item in Keys)
ListKeyData.Add(item);
return ListKeyData[ValueIndex];
return string.Empty;
【讨论】:
-1 代码过多,性能会比top answer from Kimi(比你早6年发布)更差。您不需要 foreach Keys 和 Values 属性来创建这 2 个列表(Linq 的 ToList 将为您执行此操作)。此外,如果您打算使用 IndexOf,则可以避免调用 ContainsValue(从而避免通过同一任务的所有元素进行 2 次循环)。 这个建议的表现太糟糕了。您不妨创建一个具有两个字典的泛型类。其中一个持有 Key1 和 Key2,另一个持有 Key2 和 Key1。这样,您就可以在没有...嗯...您的答案建议的所有内容的情况下获得任一密钥。【参考方案9】:我有一个非常简单的方法来做到这一点。它对我来说很完美。
Dictionary<string, string> types = new Dictionary<string, string>();
types.Add("1", "one");
types.Add("2", "two");
types.Add("3", "three");
Console.WriteLine("Please type a key to show its value: ");
string rLine = Console.ReadLine();
if(types.ContainsKey(rLine))
string value_For_Key = types[rLine];
Console.WriteLine("Value for " + rLine + " is" + value_For_Key);
【讨论】:
抱歉,您的回答不符合问题。问题是关于如何通过值找到键,您的答案显示了标准:通过键找到值以上是关于按值获取字典键的主要内容,如果未能解决你的问题,请参考以下文章