Reputation: 9153
In a Dictionary<struct,int>
: is it possible to Add/Set in one call?
So is it possible to do the code below in only one lookup per entry?
_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 better suitable data structure?
Upvotes: 7
Views: 1162
Reputation: 345
You can use the old Hashtable container :
Hashtable map = new Hashtable();
map[key] = value;
If the key does not exists, it will create and add it automatically to the map. But you will suffer from the boxing/unboxing if you use a key that is a value type...
Upvotes: -1
Reputation: 964
Roll your own Dictionary. If all you really need is an optimized setter/getter function for a specific type, then you can make your own Dictionary specialized for the purpose. The source code for the built-in Dictionary can be found here http://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,d3599058f8d79be0 if you need some reference code to get you thinking.
Upvotes: 1
Reputation: 6793
Very nasty solution, but it will be faster under the assumption you call the AddPoints()
method mostly for already existing items 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 impact your performance negatively. To avoid this, you can pre-fill the dictionary like this:
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
}
*/
}
}
Upvotes: -2
Reputation: 79631
Yes, there is a way to do this, but it has a downside. Consider this class:
class Ref<T>
{
public T Value;
}
You can use a Dictionary<K, Ref<int>> dict
and then do this:
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 additional heap object per entry in your dictionary. Depending on your situation, this may or may not be acceptable.
Upvotes: 3