50

I wanted to add a KeyValuePair<T,U> to a Dictionary<T, U> and I couldn't. I have to pass the key and the value separately, which must mean the Add method has to create a new KeyValuePair object to insert, which can't be very efficient. I can't believe there isn't an Add(KeyValuePair<T, U>) overload on the Add method. Can anyone suggest a possible reason for this apparent oversight?

yoozer8
  • 7,361
  • 7
  • 58
  • 93
Dave
  • 3,429
  • 2
  • 26
  • 29
  • 1
    There isn't this overload because a Dictionary doesn't only "insert" a new KeyValuePair. (I even doubt it's stored in that format under the hood) It tests if the Key already exist and probably perform some operation to place it at the right spot to keep queries as quick as possible. – LightStriker Oct 22 '12 at 13:17
  • 1
    You can just make an assignment: dictionary[key] = value; – jwaliszko Oct 22 '12 at 13:19
  • what is type of your key and value? – Jacek Oct 22 '12 at 13:20
  • I think you can ignore the overhead of the "Add" method. – Felix K. Oct 22 '12 at 13:23
  • you can alse use dictionary.Add(pair.key, pair.Value), where pair is KVP object – Jacek Oct 22 '12 at 13:25
  • Seems a reasonable question to me, leaving aside the 'efficiency', it's annoying to have to add the KVP by separating it out. – nicodemus13 Sep 18 '14 at 16:51
  • Interesting because it looks like Dictionary has the same ICollection interface with the same Add(KeyValuePair) method but it's not showing up as an option. I'm seeing this also. – Michael Puckett II Apr 23 '18 at 14:08

8 Answers8

50

You can use the IDictionary<TKey,TValue> interface which provides the Add(KeyValuePair<TKey,TValue>) method:

IDictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(new KeyValuePair<int,string>(0,"0"));
dictionary.Add(new KeyValuePair<int,string>(1,"1"));
DmitryG
  • 17,677
  • 1
  • 30
  • 53
  • 9
    Also note that this method does just call `Add(kvp.Key, kvp.Value)`. – Rawling Oct 22 '12 at 13:22
  • 2
    @Rawling yes, it is true in the most cases, but it depends on implementation of IDictionary interface (for example the Sorted Dictionary implements it in other manner than calling Add(kvp.Key,kvp.Value)) – DmitryG Oct 22 '12 at 13:31
40

Backup a minute...before going down the road of the oversight, you should establish whether creating a new KeyValuePair is really so inefficient.

First off, the Dictionary class is not internally implemented as a set of key/value pairs, but as a bunch of arrays. That aside, let's assume it was just a set of KeyValuePairs and look at efficiency.

The first thing to notice is that KeyValuePair is a structure. The real implication of that is that it has to be copied from the stack to the heap in order to be passed as a method parameter. When the KeyValuePair is added to the dictionary, it would have to be copied a second time to ensure value type semantics.

In order to pass the Key and Value as parameters, each parameter may be either a value type or a reference type. If they are value types, the performance will be very similar to the KeyValuePair route. If they are reference types, this can actually be a faster implementation since only the address needs to be passed around and very little copying has to be done. In both the best case and worst case, this option is marginally better than the KeyValuePair option due to the increased overhead of the KeyValuePair struct itself.

Tim Copenhaver
  • 3,282
  • 13
  • 18
  • 1
    +1 Exactly what has been in my mind. But i've been to lazy to write it down. – Felix K. Oct 22 '12 at 13:26
  • "not internally implemented as a set of key/value pairs, but as a bunch of arrays": not actually true. There is *one* array of the private member struct `Dictionary.Entry` (key, value and a couple of ints). But otherwise you're on the right track (but failed to mention *premature optimisation" :-)). – Richard Oct 22 '12 at 14:28
  • The Dictionary class uses an array of buckets and an array of entries internally to separate out the items. You're right that "a bunch" may be a bit of an overstatement, though. – Tim Copenhaver Oct 22 '12 at 15:17
  • 1
    Copying a `KeyValuePair)` has about the same cost as copying a `TKey` and a `TValue` separately. Constructing such a struct for the purpose of calling an `Add` method wouldn't be helpful, but if one is manually enumerating an `IEnumerator>`, calling `Add(myEnumerator.Current);` would be more efficient than `Add(myEnumerator.Current.Key,myEnumerator.Current.Value);` I don't see that exposing the overload would have hurt anything. – supercat Dec 12 '12 at 20:03
  • Saying "Dictionary does not internally implement KeyValuePairs internally" is at least half wrong. see https://stackoverflow.com/a/13012353/1297040 Moreover, efficiency talk is nonsense since explicit interface adds the kvp object reference with some small overhead to enforce unique key hash. – FizxMike Jul 12 '18 at 14:44
18

There is such a method – ICollection<KeyValuePair<K, T>>.Add but as it is explicitly implemented you need to cast your dictionary object to that interface to access it.

((ICollection<KeyValuePair<KeyType, ValueType>>)myDict).Add(myPair);

See

The page on this method includes an example.

Richard
  • 106,783
  • 21
  • 203
  • 265
3

Should somebody really want to do this, here is an Extension

    public static void Add<T, U>(this IDictionary<T, U> dic, KeyValuePair<T, U> KVP)
    {
        dic.Add(KVP.Key, KVP.Value);
    }

but i would recommend to not do this if there is no real need to do this

Town
  • 14,706
  • 3
  • 48
  • 72
WiiMaxx
  • 5,322
  • 8
  • 51
  • 89
2

Unless I'm mistaken, .NET 4.5 and 4.6 adds the ability to add a KeyValuePair to a Dictionary. (If I'm wrong, just notify me and I'll delete this answer.)

https://msdn.microsoft.com/en-us/library/cc673027%28v=vs.110%29.aspx

From the above link, the relevant piece of information is this code example:

public static void Main() 
{
    // Create a new dictionary of strings, with string keys, and 
    // access it through the generic ICollection interface. The 
    // generic ICollection interface views the dictionary as a 
    // collection of KeyValuePair objects with the same type 
    // arguments as the dictionary. 
    //
    ICollection<KeyValuePair<String, String>> openWith =
        new Dictionary<String, String>();

    // Add some elements to the dictionary. When elements are  
    // added through the ICollection<T> interface, the keys 
    // and values must be wrapped in KeyValuePair objects. 
    //
    openWith.Add(new KeyValuePair<String,String>("txt", "notepad.exe"));
    openWith.Add(new KeyValuePair<String,String>("bmp", "paint.exe"));
    openWith.Add(new KeyValuePair<String,String>("dib", "paint.exe"));
    openWith.Add(new KeyValuePair<String,String>("rtf", "wordpad.exe"));

    ...
}

As can be seen, a new object of type Dictionary is created and called openWith. Then a new KVP object is created and added to openWith using the .Add method.

Machtyn
  • 2,982
  • 6
  • 38
  • 64
  • 1
    `openWith` is declared as an `ICollection>`, even though it uses a `Dictionary` under the hood. That's why that `Add()` is available. – asherber Dec 28 '18 at 14:38
1

just because the enumerator for the Dictionary class returns a KeyValuePair, does not mean that is how it is implemented internally.

use IDictionary if you really need to pass KVP's because you've already got them in that format. otherwise use assignment or just use the Add method.

Mike Corcoran
  • 14,072
  • 4
  • 37
  • 49
0

What would be wrong with just adding it into your project as an extension?

namespace System.Collection.Generic
{
    public static class DictionaryExtensions
    {
        public static void AddKeyValuePair<K,V>(this IDictionary<K, V> me, KeyValuePair<K, V> other)
        {
            me.Add(other.Key, other.Value);
        }
    }
}
Machtyn
  • 2,982
  • 6
  • 38
  • 64
-2

I'm not 100% sure, but I think the internal implementation of a Dictionary is a Hash-table, which means key's are converted to hashes to perform quick look ups.

Have a read here if you want to know more about hashtables

http://en.wikipedia.org/wiki/Hash_table

Gertjan Assies
  • 1,890
  • 13
  • 23
  • 1
    While correct, this has *nothing* to do with the question. So -1. (Even hash tables need to store the original values to handle collisions and also for enumeration of the keys.) – Richard Oct 22 '12 at 13:26
  • The question clearly arose from a lack of understanding the inner workings of a Dictionary. my answer enables him to answer this and further questions himself, or at least where to look for the answer. – Gertjan Assies Oct 22 '12 at 13:34
  • 1
    I don't completely agree. Yes there are assumptions about the internal representation, but actually they are closer that your assumptions about the internal representation (it is a single array of structs of key, value and a couple of ints). Finally, the start of the answer deserves the -1: read the remarks on the MSDN page for the type, is states explicitly it is a hash table. – Richard Oct 22 '12 at 14:34