Search code examples
c#perldictionaryhashmaphashtable

How to port a multi-keys hash from perl to a c# equivalent?


While porting a perl module into c# code, I stumbled into how to port a multi-keys hash from perl to a c# equivalent:

$map{$key1}{$key2}=$value;

In the perl code to port, I can define multiple lines with the same key1, and also I can access the hash only with the first key:

# define multiple lines with the same key1 : ex :
$key1 = '1'; 
$key2 = 'a';
$map{$key1}{$key2}=54;
$key2 = 'b';
$map{$key1}{$key2}=47;

# can access the hash only with the first key : ex :
if (exists($$map{'1'}) {}

But in c# if I use a c# dictionary, I can not add a same key1 lines, it says duplicate keys. For example, in c#, if I do this, I have an error:

var map = new Dictionary<string, Dictionary<string, int>>();
map.Add(key1, new Dictionary<string, int>() { { key2, 54 } });
map.Add(key1, new Dictionary<string, int>() { { key2, 47 } });

Same wise, if I use a tuple as the key, I will be able to add 2 rows with the same key1 (and a different key2), but I will not be able to access the dictionary only with the first key:

var map = new Dictionary<Tuple<string, string>, int>();
map.Add(new Tuple<string, string>(key1, key2), 54);
map.Add(new Tuple<string, string>(key1, key2), 47);
if (map["1"] != null) {} // => this gives an error

Any idea?


Solution

  • In your root dictionary, you have to add a new entry only if it doesn't exist already. Try this:

    key1 = "1";
    key2 = "a";
    if(!map.TryGetValue(key1, out var subMap))
    {
      map[key1] = subMap = new Dictionary<string, int>();
    }
    subMap[key2] = 54;
    
    // somewhere else in code
    key1 = "1";
    key2 = "b";
    if(!map.TryGetValue(key1, out var subMap))
    {
      map[key1] = subMap = new Dictionary<string, int>();
    }
    subMap[key2] = 47;