11

有没有办法从Dictionary(by ) 中删除一个条目并在同一步骤中Key检索它?Value

例如,我打电话

Dictionary.Remove(Key);

但我也希望它同时返回值。该函数仅返回一个bool.

我知道我可以做类似的事情

Value = Dictionary[Key];
Dictionary.Remove(Key);

但似乎这将搜索字典两次(一次获取值,另一次从字典中删除它)。我怎么能(如果可能的话)在不搜索字典两次的情况下两者都做?

4

6 回答 6

7

从 .NET Core 2.0 开始,我们有:

public bool Remove (TKey key, out TValue value);

https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.remove?view=netcore-2.0#System_Collections_Generic_Dictionary_2_Remove__0__1__

请注意,此 API 尚未包含在 .NET Standard 2.0.NET Framework 4.7中。

于 2017-10-15T15:46:41.510 回答
2

因为它们都有所需的缺失方法,所以我尝试了哥本哈根大学http://www.itu.dk/research/c5/的 Microsoft 的ConcurrentDictionary和 C5 ,我可以说,至少在我的用例中它非常慢(我与 Dictionary 相比,平均慢 5 倍 - 10 倍。我认为 C5 一直在对键和值进行排序,并发字典对调用线程“太担心”了。我不是在这里讨论为什么字典的这两个化身很慢。我的算法正在寻找和替换一些条目,而第一个键将被删除并添加新键(某种队列)......唯一要做的就是修改原始.Net mscorelib 的字典。我从微软下载了源代码并包含了字典我的源代码中的类。要编译,我还需要拖动HashHelpers类和ThrowHelper类。剩下的就是注释掉一些行(例如[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]和一些资源获取)。显然我必须将缺少的方法添加到复制的类中。也不要尝试编译 Microsoft 源代码,你将这样做几个小时,我很幸运能够让它继续下去。

   public bool Remove(TKey key, out TValue value)
    {
        if (key == null)
        {
            ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
        }

        if (buckets != null)
        {
            int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
            int bucket = hashCode % buckets.Length;
            int last = -1;
            for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next)
            {
                if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))
                {
                    if (last < 0)
                    {
                        buckets[bucket] = entries[i].next;
                    }
                    else
                    {
                        entries[last].next = entries[i].next;
                    }
                    entries[i].hashCode = -1;
                    entries[i].next = freeList;
                    entries[i].key = default(TKey);
                    value = entries[i].value;
                    entries[i].value = default(TValue);
                    freeList = i;
                    freeCount++;
                    version++;
                    return true;
                }
            }
        }
        value = default(TValue);
        return false;
    }

最后,我将命名空间修改为System.Collection.Generic.My 在我的算法中,我只有两行获取值而不是在下一行中删除它。用方法替换它并获得了 7%-10% 的稳定性能增益。希望它对这个用例和从头重新实现字典不是应该做的任何其他情况有所帮助。

于 2015-12-09T18:45:01.393 回答
1

尽管这不是 OP 所要求的,但我还是忍不住发布了一个更正的扩展方法:

public static bool Remove<TKey, TValue>(this Dictionary<TKey, TValue> self, TKey key, out TValue target)
{
    self.TryGetValue(key, out target);
    return self.Remove(key);
}
于 2015-03-26T19:24:53.290 回答
1

concurrentDictionary一个TryRemove方法尝试从 中删除并返回具有指定键的值,如果键不存在,则System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>. 返回该类型的默认值。TValue

https://msdn.microsoft.com/en-us/library/dd287129(v=vs.110).aspx

于 2017-06-05T01:39:18.610 回答
0

您可以使用扩展方法来做到这一点:

public static string GetValueAndRemove<TKey, TValue>(this Dictionary<int, string> dict, int key)
{
    string val = dict[key];
    dict.Remove(key);
    return val;    
}

static void Main(string[] args)
{
    Dictionary<int, string> a = new Dictionary<int, string>();
    a.Add(1, "sdfg");
    a.Add(2, "sdsdfgadfhfg");
    string value = a.GetValueAndRemove<int, string>(1);
}
于 2013-04-15T23:30:50.843 回答
0

您可以扩展该类以添加该功能:

public class PoppableDictionary<T, V> : Dictionary<T, V>
{
    public V Pop(T key)
    {
        V value = this[key];
        this.Remove(key);
        return value;
    }
}
于 2013-04-15T23:35:21.577 回答