Multi key dictionary where only 1 key is needed to retrieve object - c#

There are several places on the internet that talk about having multy key dictionary such as in:
Multi-key dictionary in c#?
Or
Multi-key dictionaries (of another kind) in C#?
I am looking for a multi key dictionary that will enable me to retrieve the object that I am looking for as long as I provide just one key. In other words If I where to have:
// multyKeyDictionary = instance of a multikeydictionary
multyKeyDictionary.add(key1, key2, someObject);
then I will like to be able to retrive someObject as:
multyKeyDictionary[key1]; or multyKeyDictionary[key2];

Well, I don't understand why don't you just use regular dictionary and add object twice with different keys.
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("key1", obj);
dict.Add("key2", obj);
// dict["key1"] == dict["key2"]

Related

Create a Dictionary with multiple keys and get value using one of keys

I want to create a Dictionary that have a multiple keys and when I want to get value using just one or more keys.
I tried :
Dictionary<Tuple<int, string>, string> dictionary = new Dictionary<Tuple<int, string>, string>();
var Key =new Tuple<int,string>(1,"I1");
var Value = "this is a value";
dictionary.Add(Key, Value);
When I try to get value from the dictionary I Must / Should enter all the keys
Like this :
MessageBox.Show($"{dictionary[new Tuple<int, string>(1,"I1")]}");
But when I try to get value using just one of keys like this
MessageBox.Show($"{dictionary[new Tuple<int, string>(1,"")]}");
I got error, I know that this error happened cause dictionary need the full exist key to return a value.
So please anyone have any Idea about how can I create a Dictionary with multiple keys and when retrieving value using just one or more or all keys ?
Dictionaries in .NET are expected to have close to O(1) lookup times. To achieve this, they make use of the GetHashCode() and Equals() methods of the key objects. The resulting hash code is used to divide the dictionary's contents into partitions. When you look up an item, the partition is identified using the hash code, all the items in that partition with a matching hash code* are compared to the key you're looking up using the Equals() method.
Here you are trying to create a dictionary with two keys for every object. You're doing this using a Tuple to make one key. The GetHashCode() result of a Tuple is based on both of its values, so the performance of a dictionary is lost if you want to look up values by only half of the key. You would need to go through the entire dictionary comparing each individual item, rendering it little better than a list.
One solution would be to make a dictionary that has a string->int key lookup, and then the other dictionary just be int->string. This would require two lookups when using string keys, but might be a good solution.
Example:
Dictionary<string, int> stringKeyToIntKey = new Dictionary<string, int>();
Dictionary<int, string> intKeyDict = new Dictionary<int, string>();
intKeyDict[1] = "Test";
stringKeyToIntKey["I1"] = 1;
Console.WriteLine(intKeyDict[1]);
Console.WriteLine(intKeyDict[stringKeyToIntKey["I1"]]);
An add method could look like this:
public void AddEntry(int intKey, string stringKey, string value)
{
intKeyDict[intKey] = value;
stringKeyToIntKey[stringKey] = intKey;
}
And you could wrap TryGetValue to make life easier:
public bool TryGetValue(string stringKey, out string value)
{
value = null;
return stringKeyToIntKey.TryGetValue(stringKey, out int intKey) && intKeyDict.TryGetValue(intKey, out value);
}
Delete would look like this:
public void DeleteEntry(string stringKey)
{
if (stringKeyToIntKey.TryGetValue(stringKey, out int intKey))
{
intKeyDict.Remove(intKey);
stringKeyToIntKey.Remove(stringKey);
}
}
You would have to make sure that items are added and removed from both dictionaries at the same time. When you add an item to intKey, you would need to add the corresponding key mapping to stringKeyToIntKey.
Alternatively, you could have two dictionaries: one with a string key and one with an int key, and each would have the same values. Again you would have to add and remove items at the same time, and you would also have to update the values in both at the same time.
Example:
Dictionary<string, string> stringKeyDict = new Dictionary<string, string>();
Dictionary<int, string> intKeyDict = new Dictionary<int, string>();
stringKeyDict["I1"] = "hello";
intKeyDict[1] = "hello";
Console.WriteLine(stringKeyDict["I1"]);
Console.WriteLine(intKeyDict[1]);
This is my favoured approach where the values are class instances, since both dictionaries will reference the same class instances for my items, and thus changes to properties of those instances will be reflected in both. For strings, however, the first option might be better.
* Hash codes are not unique and multiple objects can potentially have the same hash code, even if their values are not the same
You can use string for dictionary keys. Let's say you want to create a key from int x = 5 and string y = "str". You can concat and split them with some separator, and create a key like this:
string key = $"{x}:{y}"
And let's say you want to get elements only by x. you can write something like this:
dictionary.Where(kvp=>kvp.Key.Contains($"{x}:"))
of course, it will not give elements in O(1) time(it will give you elements in O(n) time) but it will work. If you want to get elements in O(1) time only by x I am not sure if it's possible with one dictionary.

How to return an object Type given 2 parameters in a dictionary C#

I want to build a dictionary composed by 2 keys and 1 value. Is that possible?
Dictionary<(key1, key2), Type> dict = new Dictionary<(key1, key2), Type>();
Then I want to find in my dictionary by this 2 keys and get the Type. I tried that key1 and key2 were inside an object like this
Dictionary<Object, Type> dict = new Dictionary<Object, Type>();
Then I added into my dictionary an new instance object with the attributes like this
//myObject has many attributes that are empty and I just fill this 2 ones to build my dict
Object myObject = new Object();
myObject.Key1 = "A";
myObject.Key2 = "B";
dict.Add(myObject, (Type)objType);
But, the object that I want to find is loaded with data from DB and has probably many attributes filled.
The thing is when I use the TryGetValue returns nothing, so I think it's because is looking by the same reference which is not the same.
Well the question, how can I build my dictionary with 2 keys (STRING, STRING) and 1 return value (TYPE) in a easy way.
Thanks
Not sure what you mean by 2 keys. If you want a key containing two values, use Tuple, e.g.
Dictionary<Tuple<int, int>, string>
Another option is to use dictionary of dictionary, e.g.
Dictionary<int, Dictionary<int, string>>
I would use the following:
Dictionary<Tuple<string, string>, Type>
From the msdn page here:
http://msdn.microsoft.com/en-us/library/dd270346.aspx
I believe that the Equals method has been overridden for Tuple, so you should get key matching on the contents of the Tuple rather than the object reference.
Adding to dict would be:
dict.Add(new Tuple<string,string>(myObject.Key1, myObject.Key2), (Type)objType);

A dictionary with multiple entries with the same key [duplicate]

This question already has answers here:
C# dictionary - one key, many values
(15 answers)
Closed 8 years ago.
I need a Dictionary like object that can store multiple entries with the same key. Is this avaliable as a standard collection, or do I need to roll my own?
To clarify, I want to be able to do something like this:
var dict = new Dictionary<int, String>();
dict.Add(1, "first");
dict.Add(1, "second");
foreach(string x in dict[1])
{
Console.WriteLine(x);
}
Output:
first
second
In .NET 3.5 you can use a Lookup instead of a Dictionary.
var items = new List<KeyValuePair<int, String>>();
items.Add(new KeyValuePair<int, String>(1, "first"));
items.Add(new KeyValuePair<int, String>(1, "second"));
var lookup = items.ToLookup(kvp => kvp.Key, kvp => kvp.Value);
foreach (string x in lookup[1])
{
Console.WriteLine(x);
}
The Lookup class is immutable. If you want a mutable version you can use EditableLookup from MiscUtil.
I would recommend doing something like this:
var dict = new Dictionary<int, HashSet<string>>();
dict.Add(1, new HashSet<string>() { "first", "second" });
Dictionary<T,K> does not support such behavior and there's no collection in the base class library providing such behavior. The easiest way is to construct a composite data structure like this:
var data = new Dictionary<int, List<string>>();
As the second parameter you should use a collection which provides the qualities you are looking for, i.e. stable order ⇒ List<T>, fast access HashSet<T>, etc.
You definitely want to use NameValueCollection:
using System.Collections.Specialized;
NameValueCollection nvc = new NameValueCollection();
nvc.Add("pets", "Dog");
nvc.Add("pets", "Rabbit");
Console.WriteLine(nvc["pets"]);
//returns Dog,Rabbit
What you're looking for isn't actually a Dictionary in the traditional sense (see Associative Array).
There's no class, as far as I'm aware, that offers this in the framework (System.Linq.Lookup doesn't expose a constructor), but you could create a class yourself that implements ILookup<TKey, TElement>
You could perhaps use a Dictionary on your primary key, in which each element is a List or other collection on your secondary key. To add an item to your data structure, see if the primary key exists. If not, create a new single-item list with your Value and store it in the dictionary. If the primary key does exist, add your Value to the list that's in the dictionary.

NameValueCollection vs Dictionary<string,string> [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
IDictionary<string, string> or NameValueCollection
Any reason I should use Dictionary<string,string> instead of NameValueCollection?
(in C# / .NET Framework)
Option 1, using NameValueCollection:
//enter values:
NameValueCollection nvc = new NameValueCollection()
{
{"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"}
};
// retrieve values:
foreach(string key in nvc.AllKeys)
{
string value = nvc[key];
// do something
}
Option 2, using Dictionary<string,string>...
//enter values:
Dictionary<string, string> dict = new Dictionary<string, string>()
{
{"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"}
};
// retrieve values:
foreach (KeyValuePair<string, string> kvp in dict)
{
string key = kvp.Key;
string val = kvp.Value;
// do something
}
For these use cases, is there any advantage to use one versus the other? Any difference in performance, memory use, sort order, etc.?
They aren't semantically identical. The NameValueCollection can have duplicate keys while the Dictionary cannot.
Personally if you don't have duplicate keys, then I would stick with the Dictionary. It's more modern, uses IEnumerable<> which makes it easy to mingle with Linq queries. You can even create a Dictionary using the Linq ToDictionary() method.
NameValueCollection is string typed whereas Dictionary leverages generics to allow type variance. See Benefits of Generics.
Dictionary will be much faster. NameValueCollection allows duplicate keys. Which could be bad in certain situations, or desired in other. Dictionary does not allow duplicate keys.
From: http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
The Dictionary<(Of <(TKey, TValue>)>)
generic class provides a mapping from
a set of keys to a set of values. Each
addition to the dictionary consists of
a value and its associated key.
Retrieving a value by using its key is
very fast, close to O(1), because the
Dictionary<(Of <(TKey, TValue>)>)
class is implemented as a hash table.

C# Get Keys from a Dictionary<string, Stream>

Suppose I have a Dictionary like so:
Dictionary<string, Stream>
How can I get a list (or IEnumerable or whatever) of JUST the Keys from this dictionary? Is this possible?
I could enumerate the dictionary, and extract the keys one by one, but I was hoping to avoid this.
In my instance, the Dictionary contains a list of filenames (file1.doc, filex.bmp etc...) and the stream content of the file from another part of the application.
KeyCollection Dictionary(TKey, TValue).Keys
Dictionary(TKey, TValue).Keys
Typically you can discover these things through code-completion/IntelliSense.
Similarly, there is a Values property:
Dictionary<T,T>.Keys returns a KeyCollection. This has the IEnumerable interface.
so...
foreach(string key in Dictionary<string,Stream>.Keys)
{
}
public IEnumerable<long> ReturnSomeKeys()
{
var foo = new Dictionary<long, string>();
return foo.Keys;
}
This does what you want.

Categories