Amir
Amir

Reputation: 35

Multi-Keys Hash or Dictionary, a list of values as output

I am new to C# and need to have a general list with multiple keys.

I have three parameter which creates the key of my data. For each record (each three key) I have a set of values.

I need to have a generic list which the value of each node in the list be the values of my keys and the value of each node pointing to a list which contained the related values to that key.

Following is the example of my data and data structure which I am looking for:

Key1 Key2 Key3 Value1   Value2   Value3
0     0     0     a         b      c
0     0     1     d         e      f
0     1     1     g         h      -
<0,0,0, List(a,b,c)> ---> <0,0,1,list(d,e,f)>---> <0,1,1,List(g,h)>--->Null

I was thinking of having a hash table with multiple keys and the value which is pointing to an object that is a link list. Or creating a dictionary with these three keys and again returning a pointer to the head of link list.

I would be appreciate if someone can tell me how can I do it in C#.

Upvotes: 4

Views: 2217

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70701

First, you definitely should use Dictionary<TKey, TValue>, and not HashTable. The non-generic collection types are really just there for backward compatibility. It is better to use the generic types for new code.

As for your specific problem, you'll note that the .NET dictionary types allow only a single key. Indeed, this is typical for dictionary collections generally. Each entry in the collection is a single key/value pair.

However, you can combine three key values into a single object value and use that as a key instead. And in fact, .NET provides various Tuple classes to accomplish just that, a different class for each count of type parameters, and thus for each count of items in the object. Furthermore, these classes all implement appropriate comparisions and hashing for use as a dictionary key.

Now, applying this to your question, you have some options, depending on what you really want to do. Unfortunately, it's not really clear what you want to do. :(

If you will only ever have a maximum of three values for each triplet of key values, then I think the suggestion from commenter Mephy is fine. You could declare your collection and initialize it something like this:

Dictionary<Tuple<int, int, int>, Tuple<string, string, string>> collection =
    new Dictionary<Tuple<int, int, int>, Tuple<string, string, string>>
    {
        { Tuple.Create(0, 0, 0), Tuple.Create("a", "b", "c") },
        { Tuple.Create(0, 0, 1), Tuple.Create("d", "e", "f") },
        { Tuple.Create(0, 1, 1), Tuple.Create("g", "h", null) },
    };

Note that null is used to indicate a missing value in the dictionary's value tuple.

However, if you literally want a list object as the value, you could instead do something like this:

Dictionary<Tuple<int, int, int>, List<string>> collection =
    new Dictionary<Tuple<int, int, int>, List<string>>
    {
        { Tuple.Create(0, 0, 0), new List<string> { "a", "b", "c"} },
        { Tuple.Create(0, 0, 0), new List<string> { "d", "e", "f"} },
        { Tuple.Create(0, 0, 0), new List<string> { "g", "h" } },
    };

As far as treating the above as a list of key/value pairs, like any .NET collection type, Dictionary<TKey, TValue> can be treated as an enumeration of values, in this case via implementation of IEnumerable<KeyValuePair<TKey, TValue>> where TKey and TValue are the same types used for the dictionary object itself. So you can for example do something like this:

foreach (KeyValuePair<Tuple<int, int, int>, List<string>> kvp in collection)
{
    // here, kvp.Key will have the Tuple<int, int, int> key value
    // for the dictionary entry, while kvp.Value will have the
    // List<string> value for the same entry.
}

Note that the order of the enumeration of a dictionary type in .NET is undefined. You are not given any assurances elements will be returned in any particular order, e.g. in the order in which they were added. If you need a particular order, you'll have to impose that yourself somehow.

Finally, note in the above example the KeyValuePair<TKey, TValue> type. This is in fact just a special case of a tuple (though it pre-dates the actual Tuple... classes in .NET). I.e. it's a custom class designed specifically for the purpose of storing key/value pairs.

You can, if you want, declare such a type yourself to act as the key for your dictionary. This would have the advantage of allowing you to provide a specific, readable name for the type, and of course allowing you to avoid some of the verbosity that is involved in dealing with the Tuple... classes (the Tuple.Create() generic methods help, but declarations can still get unwieldy). Doing so comes of course at the expense of writing your own comparison and hash code.

You can find a middle ground, either by creating a class that inherits the Tuple... class you need, in which you implement just the constructor (passing the initialization parameters to the base constructor), e.g.:

class CustomKey : Tuple<int, int, int>
{
    public CustomKey(int i1, int i2, int i3) : base(i1, i2, i3) { }
}

or by simply aliasing the Tuple... type in your module with a using directive, giving the Tuple... type a locally usable name that is more readable, e.g.:

using CustomKey = System.Tuple<int, int, int>;

The former gives you easy access to the readable name anywhere in your project but does require implementing a (very short) class; the latter requires less work, but will apply only in a single source file.

Upvotes: 2

Related Questions