Is there a method or technique that allows you to insert an element into a
Dictionary<TKey, TValue> guaranteeing that the item is in the first index of that dictionary's KeyCollection.
For example:
Dictionary<String, String> dic = foo.GetOutput();
// `dic` is something like:
// {"foo", "baa"},
// {"a", "b"}
I need something like:
dic.Add("key", "value", 0);
// where `0` is the index that `key` to be inserted.
foreach(KeyValuePair<String, String> key in dic)
{
Console.WriteLine("{0} = {1}", key.Key, key.Value);
}
Output:
key = value
foo = baa
a = b
By not using a dictionary.
Dictionary<TKey, TValue> is implemented as a hash-table. The position of keys internal to the dictionary depends upon the hash-code, the means by which that hash-code was reduced further to provide an index into its internal structure, and the order of insertion in an entirely implementation-dependant way.
This isn't the only way to implement a dictionary. SortedDictionary<TKey, TValue> uses a tree structure internally and so always keeps keys in an order. In this case we still can't insert something in the beginning, rather we insert something and it gets put in the appropriate place.
If ordering is what you care about most, then you don't want a puredictionary at all. Rather you want either a List<KeyValuePair<TKey, TValue>> or you want a structure that offers both the functionality of a list and of a dictionary, which is provided by OrderedDictionary. This isn't generic, but you can easily create a generic wrapper around it (doesn't give the performance benefits of internally using generics, but does give type-safety in use).
I know it is a three years old question. But found a workaround of this problem. It may help someone
Dictionary<String, String> dic = foo.GetOutput();
dic = (new Dictionary<string, string> {{"key","value"}}).Concat(dic).ToDictionary(k => k.Key, v => v.Value);
This will insert the element in the beginning of dictionary :)
Dictionaries are unordered; elements are meant to be retrieved with a key, whose hash points to its value's location.
What you might want is a List <KeyValuePair>, whose elements can be inserted into a specific index.
List<KeyValuePair<string, string>> list = dic.ToList();
list.Insert(0, new KeyValuePair<string, string>("a", "b"));
foreach(KeyValuePair<string, string> pair in list)
Console.WriteLine("{0} = {1}", pair.Key, pair.Value);
This is not possible with Dictionary<TKey, TValue> as it presents it's values in an unordered fashion when enumerated. There is SortedDictionary<TKey, TValue> which provides ordering but it does so by using an IComparer<TKey> against the key value directly. Here you want the key to be a String and have ordering based on an int. That is not possible with either of these types.
I think you'll need to implement a new type with these very specific semantics in them. For example.
class OrderedMap<TKey, TValue> {
private readonly Dictionary<TKey, TValue> _map = new Dictionary<TKey, TValue>();
private readonly List<TKey> _list = new List<TKey>();
public void Add(TKey key, TValue value) {
if (!_map.ContainsKey(key)) {
_list.Add(key);
}
_map[key] = value;
}
public void Add(TKey key, TValue value, int index) {
if (_map.ContainsKey(key)) {
_list.Remove(key);
}
_map[key] = value;
_list.Insert(index, key);
}
public TValue GetValue(TKey key) {
return _map[key];
}
public IEnumerabe<KeyValuePair<TKey, TValue>> GetItems() {
foreach (var key in _list) {
var value = _map[key];
yield return new KeyValuePair<TKey, TValue>(key, value);
}
}
}
Note this does come with some non-trivial performance differences over a traditional Dictionary<TKey, TValue>. For example Add and Remove are slower.
Dictionary<TKey, TValue> is inherently unordered (or rather, the ordering is unpredictable and shouldn't be relied upon). If you want some sort of ordering, you need to use a different type. It's hard to recommend any particular type without knowing more about your requirements.
The Dictionary<TKey, TValue> can't be ordered.
You can try SortedDictionary<TKey, TValue> instead, but that one is ordered by the Key, not by a separate index.
The Dictionary<TKey,TValue> class does not hold items in an ordered manner, so there is no "first" item.
There is a SortedDictionary<Tkey,TValue> (.NET 4.0+), which sorts by the key, but again, this is a very vague idea of "first".
this is my solution, maybe not the best solution but it works. =)
public static ComboBox FillDropDownList(Dictionary<String, String> dictionary, ComboBox dropDown, String selecione)
{
var d = new SortedDictionary<String, String>();
d.Add("0", selecione);
foreach (KeyValuePair<string, string> pair in dictionary)
{
d.Add(pair.Key, pair.Value);
}
dropDown.DataSource = new BindingSource(d, null);
dropDown.DisplayMember = "Value";
dropDown.ValueMember = "Key";
dropDown.SelectedIndex = 0;
return dropDown;
}
A Dictionary is an un-ordered collection. You could try OrderedDictionary - http://msdn.microsoft.com/en-us/library/system.collections.specialized.ordereddictionary.aspx - which has an Insert() method which is what you're after.
Related
I have couple of methods and it keeps on expanding. So, I am planning to make it generic. Can anyone please help me with that. Atleast the method definition.
private static Dictionary<string, class1> PToDictionary(MapField<string, class1Proto> keyValuePairs)
{
Dictionary<string, class1> keyValues = new();
foreach (var pair in keyValuePairs)
{
**keyValues[pair.Key] = pToR(pair.Value);**
}
return keyValues;
}
My another method is :
private static Dictionary<Uri, class2> PToDictionary1(MapField<string, class2Proto> keyValuePairs)
{
Dictionary<string, class2> keyValues = new();
foreach (var pair in keyValuePairs)
{
**keyValues[new Uri(pair.Key)] = pToR1(pair.Value);**
}
return keyValues;
}
How can I make this generic so that when more methods are added, I dont need to add code.
I was thinking something like this, but errors are :
// Not sure how to call this method after Func is there
private static Dictionary<TKey, TValue> PToDictionary<TKey, TValue, TKeyProto, TValueProto>(MapField<TKeyProto, TValueProto> keyValuePairs, Func<TKeyProto, TKey> keyFunc, Func<TValueProto, TValue> valueFunc)
{
//How can I generalize my above method ?
}
Can someone help me complete the method ?
You don't need an extra method at all. LINQ already provides everything you need, combined with the fact that MapField implements IDictionary<TKey, TValue> (and therefore IEnumerable<KeyValuePair<TKey, TValue>>.
You'd just call:
var dictionary = repeatedField.ToDictionary(
pair => ConvertKey(pair.Key), pair => ConvertValue(pair.Value));
(where ConvertKey would be whatever code you want to convert the repeated field key into the dictionary key, and likewise for ConvertValue).
Sample calls:
var d1 = repeatedField1.ToDictionary(pair => pair.Key, pair => pToR(pair.Value));
var d2 = repeatedField2.ToDictionary(
pair => new Uri(pair.Key), pair => pToR1(pair.Value));
... but you may be able to remove the pToR and pToR1 methods anyway. (It's hard to tell without information about what they're doing...)
You can use the following method to convert MapField<TKeyProto, TValueProto> to Dictionary<TKey, TValue>:
public static Dictionary<TKey, TValue> PToDictionary<TKey, TValue, TKeyProto, TValueProto>(
MapField<TKeyProto, TValueProto> keyValuePairs,
Func<TKeyProto, TKey> mapKey,
Func<TValueProto, TValue> mapValue
)
{
Dictionary<TKey, TValue> keyValues = new();
foreach (var pair in keyValuePairs)
{
keyValues[mapKey(pair.Key)] = mapValue(pair.Value);
}
return keyValues;
}
Here, mapKey is a function that converts MapField's key to a dictionary key. Similarly, mapValue converts MapField's value to a dictionary value.
Another way is to make usage of LINQ ToDictionary extension method:
public static Dictionary<TKey, TValue> PToDictionary<TKey, TValue, TKeyProto, TValueProto>(
MapField<TKeyProto, TValueProto> keyValuePairs,
Func<TKeyProto, TKey> mapKey,
Func<TValueProto, TValue> mapValue
)
{
// this is possible because MapField<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>
return keyValuePairs.ToDictionary(
(KeyValuePair<TKeyProto, TValueProto> kvp) => mapKey(kvp.Key),
(KeyValuePair<TKeyProto, TValueProto> kvp) => mapValue(kvp.Value));
}
For example, if you want to convert MapField<string, string> to Dictionary<Uri, int> you can use the following code:
Dictionary<Uri, int> dictionary = PToDictionary(
map,
key => new Uri(key),
val => int.Parse(val));
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
I have the following method that makes a deep copy of a dictionary:
public static Dictionary<string, MyClass> deepCopyDic(Dictionary<string, MyClass> src)
{
//Copies a dictionary with all of its elements
//RETURN:
// = Dictionary copy
Dictionary<string, MyClass> dic = new Dictionary<string, MyClass>();
for (int i = 0; i < src.Count; i++)
{
dic.Add(src.ElementAt(i).Key, new MyClass(src.ElementAt(i).Value));
}
return dic;
}
I was wondering, can I somehow make it into a template? I need MyClass to be a template.
You can use Generics with where TValue : ICloneable constraint:
public static Dictionary<TKey, TValue> deepCopyDic<TKey, TValue>(Dictionary<TKey, TValue> src)
where TValue : ICloneable
{
//Copies a dictionary with all of its elements
//RETURN:
// = Dictionary copy
Dictionary<TKey, TValue> dic = new Dictionary<TKey, TValue>();
foreach (var item in src)
{
dic.Add(item.Key, (TValue)item.Value.Clone());
}
return dic;
}
You'll have to implement ICloneable interface in every class you'd like to pass into that method.
Or a bit improved version, with Key cloned as well:
public static Dictionary<TKey, TValue> deepCopyDic<TKey, TValue>(Dictionary<TKey, TValue> src)
where TValue : ICloneable
where TKey : ICloneable
{
return src.ToDictionary(i => (TKey)i.Key.Clone(), i => (TValue)i.Value.Clone());
}
You could use the copy constructor option:
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
This way you make a deep copy of your dictionary.
Link to the original post.
The Serialized approach is the only way as noted above. ICloneable does not guarantee that all properties in the object being clone is not assigning references unless you have full control over the object which is never a good assumption, especially in a large team.
The only cavet of the Serialized approach is that all objects being passed in the dictionary are serializable. Also, serializing is not always very efficient because of the over use of Reflection that occurs, which shouldn't be used in high preformance areas of code.
I solved this problem using an approach known as fast serialization but it requires that all objects that you plan to clone support a specific interface. It's always speed vs. complexity.
I currently have a menu with subitems that is being stored in this dictionary variable:
private Dictionary<string, UserControl> _leftSubMenuItems
= new Dictionary<string, UserControl>();
So I add views to the e.g. the "Customer" section like this:
_leftSubMenuItems.Add("customers", container.Resolve<EditCustomer>());
_leftSubMenuItems.Add("customers", container.Resolve<CustomerReports>());
But since I am using a Dictionary, I can only have one key named "customers".
My natural tendency would be to now create a custom struct with properties "Section" and "View", but is there a .NET collection is better suited for this task, something like a "MultiKeyDictionary"?
ANSWER:
Thanks maciejkow, I expanded your suggestion to get exactly what I needed:
using System;
using System.Collections.Generic;
namespace TestMultiValueDictionary
{
class Program
{
static void Main(string[] args)
{
MultiValueDictionary<string, object> leftSubMenuItems = new MultiValueDictionary<string, object>();
leftSubMenuItems.Add("customers", "customers-view1");
leftSubMenuItems.Add("customers", "customers-view2");
leftSubMenuItems.Add("customers", "customers-view3");
leftSubMenuItems.Add("employees", "employees-view1");
leftSubMenuItems.Add("employees", "employees-view2");
foreach (var leftSubMenuItem in leftSubMenuItems.GetValues("customers"))
{
Console.WriteLine(leftSubMenuItem);
}
Console.WriteLine("---");
foreach (var leftSubMenuItem in leftSubMenuItems.GetAllValues())
{
Console.WriteLine(leftSubMenuItem);
}
Console.ReadLine();
}
}
public class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if (!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
public List<TValue> GetValues(TKey key)
{
return this[key];
}
public List<TValue> GetAllValues()
{
List<TValue> list = new List<TValue>();
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValues(key);
list.AddRange(values);
}
return list;
}
}
}
Answer 2:
Thanks Blixt for the tip about yield, here is GetAllValues with that change:
public IEnumerable<TValue> GetAllValues()
{
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValuesForKey(key);
foreach (var value in values)
{
yield return value;
}
}
}
Answer 2 refactored further:
Here is a much more succinct way to do the same thing, thanks Keith:
public IEnumerable<TValue> GetAllValues()
{
foreach (var keyValPair in this)
foreach (var val in keyValPair.Value)
yield return val;
}
If you need variable number of values for one key, why not create Dictionary<string, List<UserControl>> ? Furthermore, you could inherit this class and create your own Add, get same syntax you're using now. This way you can avoid manual adding of empty lists before adding new control.
sth like this:
class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if(!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
}
Check out NGenerics' HashList. It's a Dictionary which maintains a list of values for each key. Wintellect's PowerCollections library also has a handy MultiDictionary class which does things like automatically clean up when you remove the last value associated with a given key.
How about making the container value type a list:
private Dictionary<string, List<UserControl>> _leftSubMenuItems =
new Dictionary<string, List<UserControl>>();
if (!_leftSubMenuItems.ContainsKey("customers"))
{
_leftSubMenuItems["customers"] = new List<UserControl>();
}
_leftSubMenuItems["customers"].Add(container.Resolve<EditCustomer>());
_leftSubMenuItems["customers"].Add(container.Resolve<CustomerReports>());
Just a few tweaks...
public class MultiValueDictionary<TKey, TValue> :
Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
List<TValue> valList;
//a single TryGetValue is quicker than Contains then []
if (this.TryGetValue(key, out valList))
valList.Add(value);
else
this.Add( key, new List<TValue> { value } );
}
//this can be simplified using yield
public IEnumerable<TValue> GetAllValues()
{
//dictionaries are already IEnumerable, you don't need the extra lookup
foreach (var keyValPair in this)
foreach(var val in keyValPair.Value);
yield return val;
}
}
The .NET framework 3.5 includes a special LINQ Lookup class.
It is similar to a dictionary except that it can handle multiple items with the same key. When you do a search using a given key, instead of receiving a single element, you receive a group of elements that match that key.
I read that it is a hashtable under the covers so it is fast for retrieving.
You use it something like this:
var example1 = (from element in ListWithDuplicates
select element)
.ToLookup(A => A.Name);
There are a bunch of caveats:
The Lookup class has no public constructor, so you cant just create a Lookup object, it seems to only be available using the .ToLookup syntax.
You cannot edit it once it has been created, no Add or Remove etc.
Apparently its not serializable
Using the grouped data can be a bit tricky
Theres a great article here discussing the Lookup and its implications in more detail.
No, there's no better built-in collection. I think your "natural tendency" is perfectly suited for solving this problem, as those are not really "same keys," but unique keys composed of different parts and Dictionary does the job. You can also nest dictionary (makes sense if you have large number of values for each name):
Dictionary<string, Dictionary<Type, object>> dict = ...;
var value = (T)dict[name][typeof(T)];
This approach will resolve to the element using a single hash table lookup. If you maintain a list of items for each element, you'll have to linearly traverse the list each time you need an element to lookup which defeats the purpose of using a Dictionary in the first place.
I don't know of a "MultiKeyDictionary". I'd recommend using a struct and overriding GetHashCode, Equals and implementing IEquatable<StructName> (which is used by Dictionary<TKey,TValue>).
Are you looking to store multiple entries per key together? Somethign like this ?