C # Dictionary Add / Install in One Call for Performance Considerations

In Dictionary<struct,int> : is it possible to Add / Install in one call?

So, is it possible to make the code below in only one search for each record?

 _KeyToPoints = new Dictionary<Key,int>(); foreach ( var entry in billionEntries ) { int originalValue; // first lookup _KeyToPoints.TryGetValue(entry.Key, out originalValue); // second lookup _KeyToPoints[key] = originalValue + points; } 

This is done in a very tight loop over a huge amount of data, so all performance matters.

Or is there a more suitable data structure?

+5
source share
4 answers

Yes, there is a way to do this, but it has a drawback. Consider this class:

 class Ref<T> { public T Value; } 

You can use Dictionary<K, Ref<int>> dict , and then do the following:

 Ref<int> count; if (!dict.TryGetValue(key, out count)) { count = new Ref<int> { Value = 0 }; dict[key] = count; } count.Value += points; 

The downside is that now you have an extra heap object to write to in the dictionary. Depending on your situation, this may or may not be acceptable.

+2
source

Collapse your dictionary. If you really need an optimized setter / getter function for a particular type, you can make your own dictionary specialized for this purpose. The source code of the built-in dictionary can be found here http://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,d3599058f8d79be0 if you need some kind of reference code so you can think about it.

+2
source

You can use the old Hashtable container:

 Hashtable map = new Hashtable(); map[key] = value; 

If the key does not exist, it will automatically create and add it to the card. But you will suffer from boxing / unboxing if you use a key that is a value type ...

0
source

A very unpleasant solution, but it will be faster on the assumption that you call the AddPoints() method mainly for existing elements in the dictionary.

 void AddPoints(T key, int points) { try { _KeyToPoints[key] = _KeyToPoints[key] + points; } catch (ArgumentException) { _KeyToPoints[key] = points; } } 

Throwing and handling exceptions is very expensive (time consuming) and will negatively affect your performance. To avoid this, you can pre-populate the dictionary as follows:

 void PreFillKeys(params T[] keys) // use an IEnumerable<T> if handier { foreach (T key in keys) { // EITHER THIS: if (!_KeyToPoints.ContainsKey(key)) _KeyToPoints[key] = 0; /* OR THIS (faster if you know none of keys was added before) try { _KeyToPoints[key] = 0; } catch (ArgumentException) { // ignore >> you shouldn't have called } */ } } 
-1
source

Source: https://habr.com/ru/post/1245650/


All Articles