Увеличение числового значения в словаре - программирование
Подтвердить что ты не робот

Увеличение числового значения в словаре

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

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

4b9b3361

Ответ 1

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

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

someDictionary.AddOrUpdate(id, 1, (id, count) => count + 1);  

Ответ 2

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

int currentCount;

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

someDictionary[id] = currentCount + 1;

Это зависит от того, что метод TryGetValue устанавливает значение value в значение по умолчанию его типа, если ключ doesn ' t существует. В вашем случае значение по умолчанию int равно 0, что именно то, что вы хотите.


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

// declare variable right where it passed
someDictionary.TryGetValue(id, out var currentCount); 
someDictionary[id] = currentCount + 1;

Ответ 3

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

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

Ответ 4

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

Говоря это, немного более короткая версия:

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

    someDictionary[id]++;
}

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

Ответ 5

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

Это не совсем ответ на ваш вопрос, но для полноты я измерил поведение различных классов, полезных для приращения целых чисел на основе целых ключей: simple Array, Dictionary (подход @Ani), Dictionary (простой подход), SortedDictionary (подход @Ani) и 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 в три раза медленнее, чем Dictionary TryGetValue + установщик индексатора. И последнее в десять раз медленнее, чем Array.

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

Ответ 6

Вот удобный unit test для вас, чтобы играть в отношении 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);
     }