11

Dictionary(by )からエントリを削除し、同じステップでKeyそのエントリを取得する方法はありますか?Value

たとえば、私は電話しています

Dictionary.Remove(Key);

しかし、同時に値を返すことも望んでいます。この関数は のみを返しますbool

私は次のようなことができることを知っています

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

しかし、これは辞書を2回検索するようです(1回は値を取得し、もう1回は辞書から削除します)。どうすれば(可能であれば)辞書を2回検索せずに両方を行うことができますか?

4

6 に答える 6

7

.NET Core 2.0 以降では、次の機能があります。

public bool Remove (TKey キー、TValue 値から);

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 は常にキーと値の両方を並べ替えており、Concurrent Dictionary は呼び出しスレッドについて「心配しすぎている」と思います。私のアルゴリズムはいくつかのエントリを探して置き換えていましたが、最初のキーは削除され、新しいキーが追加されました (ある種のキュー)...あとは、元の .Net mscorelib の辞書を変更することだけでした。Microsoft からソース コードをダウンロードし、辞書を含めました私のソースコードのクラス。コンパイルするには、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 。私のアルゴリズムでは、次の行で値を削除するよりも値を取得していた行が 2 行しかありませんでした。それを新しいメソッドに置き換え、7% ~ 10% の安定したパフォーマンス向上を得ました。このユースケースや、ディクショナリを最初から再実装することが適切でない他のケースに役立つことを願っています。

于 2015-12-09T18:45:01.393 に答える
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 に答える