Nice programing

사전에서 숫자 값 증가

nicepro 2020. 11. 19. 21:58
반응형

사전에서 숫자 값 증가


아래 코드를 사용하여 사전에 값을 늘리거나 삽입합니다. 증가하는 키가 존재하지 않는 경우 값을 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;
     }
 }

이것이 적절한 방법입니까?


편리한 upsert 메소드 인 AddOrUpdate가있는 ConcurrentDictionary를 사용하는 것이 이치에 맞았습니다.

그래서 방금 사용했습니다.

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

귀하의 코드는 괜찮습니다. 그러나 다음은 코드에서 분기 할 필요가없는 방식으로 단순화하는 방법입니다.

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;

읽기 쉽고 의도가 명확합니다. 괜찮다고 생각합니다. 더 똑똑하거나 더 짧은 코드를 발명 할 필요가 없습니다. 초기 버전만큼 명확하게 의도를 유지하지 않으면 :-)

즉, 다음은 약간 더 짧은 버전입니다.

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

    someDictionary[id]++;
}

사전에 동시에 액세스 할 수있는 경우 사전에 대한 액세스를 동기화해야합니다.


다음은 멋진 확장 방법입니다.

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

정수 키에 대한 .NET 4의 일부 측정입니다.

귀하의 질문에 대한 대답은 아니지만 완전성을 위해 정수 키를 기반으로 정수를 증가시키는 데 유용한 다양한 클래스의 동작을 측정했습니다. simple Array, Dictionary(@Ani의 접근 방식), Dictionary(단순한 접근 방식), SortedDictionary(@Ani의 접근 방식) ) 및 ConcurrentDictionary.TryAddOrUpdate.

다음은 직접 사용하는 대신 클래스로 래핑하기 위해 2.5ns로 조정 된 결과입니다.

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

And that's the code.

Note that ConcurrentDictionary.TryAddOrUpdate is three times slower than Dictionary's TryGetValue + indexer's setter. And the latter is ten times slower than Array.

So I would use an array if I know the range of keys is small and a combined approach otherwise.


Here is a handy unit test for you to play with concerning ConcurrentDictionary and how to keep the values threadsafe:

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

참고URL : https://stackoverflow.com/questions/7132738/incrementing-a-numerical-value-in-a-dictionary

반응형