Get KeyValuePair by Key from a ConcurrentDictionary (in O(1) time)

这一生的挚爱 提交于 2020-04-30 02:17:11

问题


As per this solution (https://stackoverflow.com/a/18923091/529618) I am using a ConcurrentDictionary<T,byte> as a workaround for the lack of ConcurrentHashSet<T>. However, I'm struggling to see how I can get the original T Key back out of the dictionary in O(1) time.

var cache = new ConcurrentDictionary<MyEquatableClass, byte>());
//...
if(!cache.TryAdd(classInstance, Byte.MinValue))
    return /* Existing cache entry */;
return classInstance;

Is there any way to get the KeyValuePair<K,V> (or even just the key) for a ConcurrentDictionary<K,V> entry by giving it an equivalent (IEquatable) key, without enumerating through it in O(n) time?

My problem arises because the objects I'm using as Keys are IEquatable<K> to one another, but not ReferenceEqual to one-another. If myDict.ContainsKey(someEquatable), I want to get the original key instance in the dictionary (as well as the value stored with it), and throw away my current (duplicate) instance.


回答1:


I just realized I could just switch from using a ConcurrentDictionary<TKey, byte> to a ConcurrentDictionary<TKey, TKey>. It may have a bit of a heavier footprint than the byte value (unconfirmed), but if the value and key are the same, I can easily get the key from the value.

To extend this to those finding this question and who are actually using the "value", you can opt to change your dictionary to a ConcurrentDictionary<TKey, Tuple<TKey, TValue>, and get both the original key and the value that way.

var cache = new ConcurrentDictionary<MyEquatableClass, MyEquatableClass>());
//...
if(!cache.TryAdd(classInstance, classInstance))
    return cache[classInstance];
return classInstance;



回答2:


Here is an extension method for adding values to a ConcurrentDictionary<T, T> that is used as a ConcurrentHashSet<T> (having the values equal to the keys):

/// <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);
}

Usage example:

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}");

Output:

dict.GetOrAdd("abc"): abc
dict.GetOrAdd("ABC"): abc
dict.Count: 1


来源:https://stackoverflow.com/questions/61085397/get-keyvaluepair-by-key-from-a-concurrentdictionary-in-o1-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!