Ich verwende den folgenden Code, um einen Wert in ein Wörterbuch zu erhöhen oder einzufügen. Wenn der Schlüssel, den ich inkrementiere, nicht vorhanden ist, möchte ich seinen Wert auf 1 setzen.
public void IncrementCount(Dictionary<int, int> someDictionary, int id)
{
int currentCount;
if (someDictionary.TryGetValue(id, out currentCount))
{
someDictionary[id] = currentCount + 1;
}
else
{
someDictionary[id] = 1;
}
}
Ist dies ein angemessener Weg?
c#
dictionary
KingNestor
quelle
quelle
Antworten:
Wie sich herausstellte, war es sinnvoll, das ConcurrentDictionary zu verwenden, das über die praktische Upsert-Methode verfügt: AddOrUpdate.
Also habe ich gerade verwendet:
someDictionary.AddOrUpdate(id, 1, (id, count) => count + 1);
quelle
Ihr Code ist in Ordnung. Aber hier ist eine Möglichkeit, um auf eine Weise zu vereinfachen, die keine Verzweigung in Ihrem Code erfordert:
int currentCount; // currentCount will be zero if the key id doesn't exist.. someDictionary.TryGetValue(id, out currentCount); someDictionary[id] = currentCount + 1;
Dies hängt davon ab, dass die
TryGetValue
Methodevalue
den Standardwert ihres Typs festlegt , wenn der Schlüssel nicht vorhanden ist. In Ihrem Fall von dem Standardwertint
ist0
, das ist genau das, was Sie wollen.UPD . Ab C # 7.0 kann dieses Snippet verkürzt werden mit
out variables
:// declare variable right where it's passed someDictionary.TryGetValue(id, out var currentCount); someDictionary[id] = currentCount + 1;
quelle
currentCount
wird0
. Das heißt aber auch,someDictinary[id]
einen zu werfenKeyNotFoundException
.Hier ist eine schöne Erweiterungsmethode:
public static void Increment<T>(this Dictionary<T, int> dictionary, T key) { int count; dictionary.TryGetValue(key, out count); dictionary[key] = count + 1; }
Verwendung:
var dictionary = new Dictionary<string, int>(); dictionary.Increment("hello"); dictionary.Increment("hello"); dictionary.Increment("world"); Assert.AreEqual(2, dictionary["hello"]); Assert.AreEqual(1, dictionary["world"]);
quelle
Es ist lesbar und die Absicht ist klar. Ich denke das ist in Ordnung. Sie müssen keinen intelligenteren oder kürzeren Code erfinden. wenn es die Absicht nicht genauso klar hält wie deine ursprüngliche Version :-)
Davon abgesehen ist hier eine etwas kürzere Version:
public void IncrementCount(Dictionary<int, int> someDictionary, int id) { if (!someDictionary.ContainsKey(id)) someDictionary[id] = 0; someDictionary[id]++; }
Wenn Sie gleichzeitig auf das Wörterbuch zugreifen, denken Sie daran, den Zugriff darauf zu synchronisieren.
quelle
ContainsKey
Ansatz mit Werttypen, wenn ich sie "modifizieren" muss. Ihr Ansatz benötigt jedoch 3 Suchvorgänge, wenn die ID nicht enthalten ist. Sie sollten verwendenif...else...
. Es ist noch besser lesbar, wenn Sie verwendenif(someDictionary.ContainsKey(id)) someDictionary[id]++; else someDictionary.Add(id, 1);
.Nur einige Messungen unter .NET 4 für Ganzzahlschlüssel.
Es ist keine vollständige Antwort auf Ihre Frage, aber der Vollständigkeit halber habe ich das Verhalten verschiedener Klassen gemessen, die zum Inkrementieren von Ganzzahlen basierend auf Ganzzahlschlüsseln nützlich sind: einfach
Array
,Dictionary
(@ Anis Ansatz),Dictionary
(einfacher Ansatz),SortedDictionary
(@ Anis Ansatz) ) undConcurrentDictionary.TryAddOrUpdate
.Hier sind die Ergebnisse, angepasst um 2,5 ns für das Umschließen mit Klassen anstelle der direkten Verwendung:
Array 2.5 ns/inc Dictionary (@Ani) 27.5 ns/inc Dictionary (Simple) 37.4 ns/inc SortedDictionary 192.5 ns/inc ConcurrentDictionary 79.7 ns/inc
Und das ist der Code .
Beachten Sie, dass
ConcurrentDictionary.TryAddOrUpdate
dreimal langsamer als istDictionary
s‘TryGetValue
+ Indexer Setter ist. Und letzteres ist zehnmal langsamer als Array.Ich würde also ein Array verwenden, wenn ich weiß, dass der Tastenbereich klein ist und ansonsten ein kombinierter Ansatz.
quelle
Hier ist ein praktischer Komponententest, mit dem Sie in Bezug auf ConcurrentDictionary spielen und wie Sie die Werte threadsicher halten können:
ConcurrentDictionary<string, int> TestDict = new ConcurrentDictionary<string,int>(); [TestMethod] public void WorkingWithConcurrentDictionary() { //If Test doesn't exist in the dictionary it will be added with a value of 0 TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1); //This will increment the test key value by 1 TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1); Assert.IsTrue(TestDict["Test"] == 1); //This will increment it again TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1); Assert.IsTrue(TestDict["Test"] == 2); //This is a handy way of getting a value from the dictionary in a thread safe manner //It would set the Test key to 0 if it didn't already exist in the dictionary Assert.IsTrue(TestDict.GetOrAdd("Test", 0) == 2); //This will decriment the Test Key by one TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue-1); Assert.IsTrue(TestDict["Test"] == 1); }
quelle
Wenn Sie nach einer verkürzten Version suchen:
someDictionary.Add(id, someDictionary.GetValueOrDefault(id, 0) + 1);
quelle