从 ConcurrentDictionary 按键获取 KeyValuePair(在 O(1) 时间内)
Get KeyValuePair by Key from a ConcurrentDictionary (in O(1) time)
根据此解决方案 (),我使用 ConcurrentDictionary<T,byte>
作为缺少 ConcurrentHashSet<T>
的解决方法。但是,我正在努力了解如何在 O(1) 时间内从字典中取出原来的 T Key
。
var cache = new ConcurrentDictionary<MyEquatableClass, byte>());
//...
if(!cache.TryAdd(classInstance, Byte.MinValue))
return /* Existing cache entry */;
return classInstance;
有什么方法可以通过给 ConcurrentDictionary<K,V>
条目一个等效的(IEquatable)键来获取 KeyValuePair<K,V>
(甚至只是键),而不用在 O(n ) 时间?
我的问题出现是因为我用作键的对象是彼此 IEquatable<K>
,而不是彼此 ReferenceEqual
。如果myDict.ContainsKey(someEquatable)
,我想获取字典中的原始键实例(以及与其存储的值),并丢弃我当前(重复)的实例。
我刚刚意识到我可以从使用 ConcurrentDictionary<TKey, byte>
切换到 ConcurrentDictionary<TKey, TKey>
。它可能比字节值(未确认)占用更多空间,但如果值和密钥相同,我可以轻松地从值中获取密钥。
为了将此扩展到那些发现这个问题和实际使用 "value" 的人,您可以选择将字典更改为 ConcurrentDictionary<TKey, Tuple<TKey, TValue>
,并同时获取原始键和对应的值方式。
var cache = new ConcurrentDictionary<MyEquatableClass, MyEquatableClass>());
//...
if(!cache.TryAdd(classInstance, classInstance))
return cache[classInstance];
return classInstance;
这是一个扩展方法,用于将值添加到用作 ConcurrentHashSet<T>
的 ConcurrentDictionary<T, T>
(具有等于键的值):
/// <summary>
/// Adds a value to a <see cref="ConcurrentDictionary{T,T}"/>
/// used as a concurrent <see cref="HashSet{T}"/>, if it does not already exist.<br/>
/// Returns the new value, or the existing value if the value exists.
/// </summary>
/// <param name="value">The value to be added, if it does not already exist.</param>
public static T GetOrAdd<T>(this ConcurrentDictionary<T, T> source, T value)
{
return source.GetOrAdd(value, value);
}
用法示例:
var dict = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Console.WriteLine($"dict.GetOrAdd(\"abc\"): {dict.GetOrAdd("abc")}");
Console.WriteLine($"dict.GetOrAdd(\"ABC\"): {dict.GetOrAdd("ABC")}");
Console.WriteLine($"dict.Count: {dict.Count}");
输出:
dict.GetOrAdd("abc"): abc
dict.GetOrAdd("ABC"): abc
dict.Count: 1
根据此解决方案 (),我使用 ConcurrentDictionary<T,byte>
作为缺少 ConcurrentHashSet<T>
的解决方法。但是,我正在努力了解如何在 O(1) 时间内从字典中取出原来的 T Key
。
var cache = new ConcurrentDictionary<MyEquatableClass, byte>());
//...
if(!cache.TryAdd(classInstance, Byte.MinValue))
return /* Existing cache entry */;
return classInstance;
有什么方法可以通过给 ConcurrentDictionary<K,V>
条目一个等效的(IEquatable)键来获取 KeyValuePair<K,V>
(甚至只是键),而不用在 O(n ) 时间?
我的问题出现是因为我用作键的对象是彼此 IEquatable<K>
,而不是彼此 ReferenceEqual
。如果myDict.ContainsKey(someEquatable)
,我想获取字典中的原始键实例(以及与其存储的值),并丢弃我当前(重复)的实例。
我刚刚意识到我可以从使用 ConcurrentDictionary<TKey, byte>
切换到 ConcurrentDictionary<TKey, TKey>
。它可能比字节值(未确认)占用更多空间,但如果值和密钥相同,我可以轻松地从值中获取密钥。
为了将此扩展到那些发现这个问题和实际使用 "value" 的人,您可以选择将字典更改为 ConcurrentDictionary<TKey, Tuple<TKey, TValue>
,并同时获取原始键和对应的值方式。
var cache = new ConcurrentDictionary<MyEquatableClass, MyEquatableClass>());
//...
if(!cache.TryAdd(classInstance, classInstance))
return cache[classInstance];
return classInstance;
这是一个扩展方法,用于将值添加到用作 ConcurrentHashSet<T>
的 ConcurrentDictionary<T, T>
(具有等于键的值):
/// <summary>
/// Adds a value to a <see cref="ConcurrentDictionary{T,T}"/>
/// used as a concurrent <see cref="HashSet{T}"/>, if it does not already exist.<br/>
/// Returns the new value, or the existing value if the value exists.
/// </summary>
/// <param name="value">The value to be added, if it does not already exist.</param>
public static T GetOrAdd<T>(this ConcurrentDictionary<T, T> source, T value)
{
return source.GetOrAdd(value, value);
}
用法示例:
var dict = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Console.WriteLine($"dict.GetOrAdd(\"abc\"): {dict.GetOrAdd("abc")}");
Console.WriteLine($"dict.GetOrAdd(\"ABC\"): {dict.GetOrAdd("ABC")}");
Console.WriteLine($"dict.Count: {dict.Count}");
输出:
dict.GetOrAdd("abc"): abc
dict.GetOrAdd("ABC"): abc
dict.Count: 1