Увеличение числового значения в словаре - PullRequest
58 голосов
/ 20 августа 2011

Я использую приведенный ниже код для увеличения или вставки значения в словарь.Если инкрементный ключ не существует, я бы хотел установить его значение равным 1.

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

Это подходящий способ сделать это?

Ответы [ 6 ]

77 голосов
/ 20 августа 2011

Как оказалось, имеет смысл использовать ConcurrentDictionary, который имеет удобный метод upsert: AddOrUpdate.

Итак, я просто использовал:

someDictionary.AddOrUpdate(id, 1, (id, count) => count + 1);  
57 голосов
/ 20 августа 2011

Ваш код в порядке. Но вот способ упростить способ, который не требует ветвления в вашем коде:

int currentCount;

// currentCount will be zero if the key id doesn't exist..
someDictionary.TryGetValue(id, out currentCount); 

someDictionary[id] = currentCount + 1;

Это зависит от того факта, что метод TryGetValue устанавливает value в значение по умолчанию своего типа, если ключ не существует. В вашем случае значение по умолчанию int равно 0, и это именно то, что вам нужно.


UPD . Начиная с C # 7.0 этот фрагмент может быть сокращен с помощью out variables:

// declare variable right where it's passed
someDictionary.TryGetValue(id, out var currentCount); 
someDictionary[id] = currentCount + 1;
14 голосов
/ 20 августа 2011

Это читабельно, и цель ясна.Я думаю, что это хорошо.Не нужно придумывать какой-нибудь более умный или короткий код;если он не сохраняет намерение таким же ясным, как ваша первоначальная версия :-)

При этом ниже приводится несколько более короткая версия:

public void IncrementCount(Dictionary<int, int> someDictionary, int id)
{
    if (!someDictionary.ContainsKey(id))
        someDictionary[id] = 0;

    someDictionary[id]++;
}

Если у вас есть одновременный доступсловарь, не забудьте синхронизировать доступ к нему.

13 голосов
/ 20 февраля 2012

Вот хороший метод расширения:

    public static void Increment<T>(this Dictionary<T, int> dictionary, T key)
    {
        int count;
        dictionary.TryGetValue(key, out count);
        dictionary[key] = count + 1;
    }

Использование:

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"]);
5 голосов
/ 24 января 2017

Только некоторые измерения в .NET 4 для целочисленных ключей.

Это не совсем ответ на ваш вопрос, но ради полноты я измерил поведение различных классов, полезных для приращения целых чисел, на основе целочисленных ключей: простые Array, Dictionary (подход @ Ani), Dictionary (простой подход), * ​​1006 * (подход @ Ани) и ConcurrentDictionary.TryAddOrUpdate.

Вот результаты, скорректированные на 2,5 нс для переноса с классами вместо прямого использования:

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

И это код .

Обратите внимание, что ConcurrentDictionary.TryAddOrUpdate в три раза медленнее, чем установщик TryGetValue + индексатора Dictionary. И последний в десять раз медленнее, чем массив.

Таким образом, я бы использовал массив, если бы знал, что диапазон ключей невелик, а в противном случае комбинированный подход.

1 голос
/ 16 июля 2015

Вот удобный для вас модульный тест, касающийся ConcurrentDictionary и того, как сохранить значения в потоке:

     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);
     }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...