C# dictionary - one key, many values

Viewed 130102

I want to create a data store to allow me to store some data.

The first idea was to create a dictionary where you have one key with many values, so a bit like a one-to-many relationship.

I think the dictionary only has one key value.

How else could I store this information?

15 Answers

You can use a list for the second generic type. For example a dictionary of strings keyed by a string:

Dictionary<string, List<string>> myDict;

Your dictionary's value type could be a List, or other class that holds multiple objects. Something like

Dictionary<int, List<string>>

for a Dictionary that is keyed by ints and holds a List of strings.

A main consideration in choosing the value type is what you'll be using the Dictionary for. If you'll have to do searching or other operations on the values, then maybe think about using a data structure that helps you do what you want -- like a HashSet.

You could use a Dictionary<TKey, List<TValue>>.

That would allow each key to reference a list of values.

Use a dictionary of lists (or another type of collection), for example:

var myDictionary = new Dictionary<string, IList<int>>();

myDictionary["My key"] = new List<int> {1, 2, 3, 4, 5};

You can create a very simplistic multi-dictionary, which automates to process of inserting values like this:

public class MultiDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
    public void Add(TKey key, TValue value)
    {
        if (TryGetValue(key, out List<TValue> valueList)) {
            valueList.Add(value);
        } else {
            Add(key, new List<TValue> { value });
        }
    }
}

This creates an overloaded version of the Add method. The original one allows you to insert a list of items for a key, if no entry for this entry exists yet. This version allows you to insert a single item in any case.

You can also base it on a Dictionary<TKey, HashSet<TValue>> instead, if you don't want to have duplicate values.

You can have a dictionary with a collection (or any other type/class) as a value. That way you have a single key and you store the values in your collection.

A .NET dictionary does only have a one-to-one relationship for keys and values. But that doesn't mean that a value can't be another array/list/dictionary.

I can't think of a reason to have a one-to-many relationship in a dictionary, but obviously there is one.

If you have different types of data that you want to store to a key, then that sounds like the ideal time to create your own class. Then you have a one-to-one relationship, but you have the value class storing more that one piece of data.

You can also use;

 List<KeyValuePair<string, string>> Mappings;

Take a look at MultiValueDictionary from Microsoft.

Example Code:

MultiValueDictionary<string, string> Parameters = new MultiValueDictionary<string, string>();

Parameters.Add("Malik", "Ali");
Parameters.Add("Malik", "Hamza");
Parameters.Add("Malik", "Danish");

//Parameters["Malik"] now contains the values Ali, Hamza, and Danish

You can declare an dictionary with <T,T[]> type, (when T = any type you want) When you initialize the values of dictionary items, declare an array each key.

For Example:

 `Dictionary<int, string[]> dictionaty  = new Dictionary<int, string[]>() {
                {1, new string[]{"a","b","c"} },
                {2, new string[]{"222","str"} }
            }; `

The proper solution is to have a Dictionary<TKey1, TKey2, TValue>, where 2 keys are needed to access a certain item. Solutions using Dictionary<TKey, List<TValue>> will create as many lists as there are unique values for TKey, which takes a lot of memory and slows down the performance. The other problem when having only 1 key is that it becomes difficult to remove one particular item.

Since I couldn't find such a class, I wrote one myself:

  public class SortedBucketCollectionClass<TKey1, TKey2, TValue>:
    IEnumerable<TValue>, ICollection<TValue>, 
    IReadOnlySortedBucketCollection<TKey1, TKey2, TValue>
    where TKey1 : notnull, IComparable<TKey1>
    where TKey2 : notnull, IComparable<TKey2>
    where TValue : class {...}

It supports access with only TKey1, which returns an enumerator over all items having TKey1 and access with TKey1, TKEy2, which returns a particular item. There are also enumerators over all stored items and one that enumerates all items with a certain range of TKey. This is convenient, when TKey1 is DateTime and one wants all items from a certain week, month or year.

I wrote a detailed article on CodeProject with code samples: SortedBucketCollection: A memory efficient SortedList accepting multiple items with the same key

You can get the source code on CodeProject or Github: StorageLib/StorageLib/SortedBucketCollection.cs

Related