0

I want to achieve the following. A Dictionary like data structure, that I initialize with var m = new MultiMap<string, int, bool>(); and then I should be able to access it using m[string1] or m[int1] while string1 is a string and int1 is an int. Of course if I need to add a value, I'd need to do something like this m.add(string2, int2, bool2) so that both of the keys are not null. Is there something similar already available? Thanks and cheers!

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • 3
    List>() should do what you want. You can LINQ select/where clauses on Item1(String), Item2(Int32) and Item3(Boolean) then. – Rick Burns Aug 20 '15 at 19:05
  • See http://stackoverflow.com/q/689940/2076784 and http://stackoverflow.com/q/1171812/2076784. – George Paoli Aug 20 '15 at 19:08
  • I'd simply go for an implementation with two underlying dictionaries unless you have memory constraints. – Lucas Trzesniewski Aug 20 '15 at 19:14
  • I would also use a Tuple unless there were some weird constraints to follow. – Keefe Higgins Aug 20 '15 at 19:25
  • Do your `int` and `string` keys have any particular significance? Perhaps if you explain your underlying requirement, it will help provide you a better answer. – sstan Aug 22 '15 at 02:06
  • I get that you want a multi-type key. What is the type of value that the Dictionary will return when you request, for example, `m[int1]`? bool? – displayName Aug 22 '15 at 05:22

2 Answers2

0

You simply can't have two keys for an item. When you add an item to a Dictionary with a key and a value, internally hash code of that key is generated by calling GetHashCode method of that key and value is stored with that hash code. So if you can somehow map your string and int keys to same hash code then only you would be able to access your value with any of the one key. So if it is possible then the best you can do is implement a Key class with three constructures, one for string, one for int and one for both. Then implement IEqualityComparer, pass it to the constructure of Dictionary.

Deepak Bhatia
  • 1,090
  • 1
  • 8
  • 13
0

You can roll your own pretty quickly, so here is an partially finished class: (I thought I'd give you a little head start, and you could take it from here.)

public class MultiKeyDictionary<T>
{
    private Dictionary<int, T> _indexDictionary = new Dictionary<int, T>();
    private Dictionary<string, T> _keyDictionary = new Dictionary<string, T>();

    public int Count
    {
        get { return _indexDictionary.Count; }
    }

    public T this[string key]
    {
        get
        {
            T result;
            if (!TryGetValue(key, out result))
            {
                throw new IndexOutOfRangeException();
            }
            return result;
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public T this[int key]
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public void Add(int index, string key, T value)
    {
        _indexDictionary.Add(index, value);
        _keyDictionary.Add(key, value);
    }

    public void Clear()
    {
        _indexDictionary.Clear();
        _keyDictionary.Clear();
    }

    public bool Contains(T item)
    {
        return _indexDictionary.ContainsValue(item);
    }

    public bool Remove(string key)
    {
        throw new NotImplementedException();
    }

    public bool Remove(int key)
    {
        throw new NotImplementedException();
    }


    public bool TryGetValue(string key, out T value)
    {
        var result = _keyDictionary.TryGetValue(key, out value);

        return result;
    }

    public bool TryGetValue(int key, out T value)
    {
        var result = _indexDictionary.TryGetValue(key, out value);

        return result;
    }
}

You can then:

var m = new MultiKeyDictionary<bool>();
m.add(int2, string2, bool2)

and access it like:

var mystring = m[string1];
var myint = m[int1];

Although I'm a fan of defensive programming and tend to use the TryGetValue() methods:

bool value;
if (m.TryGetValue(string1, out value))
{
  // value exists, I don't get an IndexOutOfRangeException
}

bool value;
if (m.TryGetValue(int1, out value))
{
  // value exists, I don't get an IndexOutOfRangeException
}
Erik Philips
  • 53,428
  • 11
  • 128
  • 150