Question on using List - c#

I created an List like this
List<Dictionary<DicKeyCla, DicValCla>>
public Class DicKeyCla
{
public EnKey1 DicKeyItem1,
public EnKey2 DicKeyItem2,
}
public enum EnKey1
{
A1,
A2,
A3,
A4,
A5
}
public enum EnKey2
{
B11,
B12,
B13,
B14,
B15,
B16,
B17,
B18,
B19,
}
As I know, there is contains() method available for List class.
If I called an function which argues contain the DicKeyCla members like A3 and B15.
How can I pick out the entirely dictionary member from the Top level List rapidly?
I need do more operation on dictionary member.

Here's the easy way to do it:
public static Dictionary<DicKeyCla, DicValCla>
FindDict(List<Dictionary<DicKeyCla, DicValCla>> haystack,
DicKeyCla needle)
{
foreach (Dictionary<DicKeyCla, DicValCla> dict in haystack)
if (dict.ContainsKey(needle))
return dict;
return null;
}
Given a list of dictionaries and a key, it will return the first dictionary that has that key, or null if none in the list do.
Or more generically:
public static IDictionary<TKey, TValue>
FindDict<TKey, TValue>(IEnumerable<IDictionary<TKey, TValue>> haystack,
TKey needle)
{
foreach (IDictionary<TKey, TValue> dict in haystack)
if (dict.ContainsKey(needle))
return dict;
return null;
}
If you need to do this lookup frequently or the list is very long, you may need to index your keys with a Dictionary<DicKeyCla, Dictionary<DicKeyCla, DicValCla>> that holds which dictionary contains which key. If multiple dictionaries can contain the same key then you would need a Dictionary<DicKeyCla, List<Dictionary<DicKeyCla, DicValCla>>> to store your index.
If you already have the list and want to create an index, you could do this:
Dictionary<DicKeyCla, Dictionary<DicKeyCla, DicValCla>> index =
new Dictionary<DicKeyCla, Dictionary<DicKeyCla, DicValCla>>();
foreach (Dictionary<DicKeyCla, DicValCla> dict in list)
foreach (KeyValuePair<DicKeyCla, DicValCla> item in dict)
index[item.Key] = dict;
// or in LINQ
Dictionary<DicKeyCla, Dictionary<DicKeyCla, DicValCla>> index =
(from dict in list
from item in dict
select new { item.Key, dict })
.ToDictionary(e => e.Key, e => e.dict);
And here's how you'd use the index:
public static Dictionary<DicKeyCla, DicValCla>
FindDict(Dictionary<DicKeyCla, Dictionary<DicKeyCla, DicValCla>> index,
DicKeyCla needle)
{
Dictionary<DicKeyCla, DicValCla> result;
index.TryGetValue(needle, out result);
return result;
}

The List.Contains method would only check if the parameter you send it is an item in the list.
If you want to be able to find an entire dictionary that contains some given A3 or B15 from this data strcuture, you will have to implement this yourself.
You can do something like manage an internal dictionary that would keep mapping from various A3/B15/etc objects to Lists of Dictionaries to which they have been added.
If O(1) search is not very important to you, consider favoring simplicity over performance, and just scan the list.

I have a strange feeling (but I'm probably wrong) that you wrapped your Dictionary with a List hoping you could search the 1 instance of the dictionary with the Contains method and all you want is to access the dictionary members by a combination of EnKey1 and EnKey2. Something like this:
public struct Key // note the struct...
{
public static Key A(EnKey1 k1, EnKey2 k2)
{
Key k = new Key();
k.Key1 = k1;
k.Key2 = k2;
return k;
}
public EnKey1 Key1;
public EnKey2 Key2;
}
Dictionary<Key, string> dic = new Dictionary<Key, string>();
dic.Add(Key.A(EnKey1.A1,EnKey2.B19), "test");
Console.WriteLine(dic[Key.A(EnKey1.A1,EnKey2.B19)]);
// outputs "test"
// then you can do:
// dic.ContainsKey(Key.A(EnKey1.A1,EnKey2.B19)) -> true
// dic.ContainsKey(Key.A(EnKey1.A2,EnKey2.B19)) -> false

Related

Dictionary extension method for specfic value type? e.g. Dictionary<T, List<U>>

Is it possible to write an extension method that works only with dictionaries that have a List as value?
I want to write one that checks if the key is existent, it will add another entry to the list. And if the key is not existent a new list is initialized, the entry added, and then everything added to the dictionary.
Now I am not sure what the method head looks like or if it is even possible to limit the function to a specific value type.
Yes, of course. In the extension method defintition you use List<T>, which the T defined in the type arguments. In this case named TListValue to avoid ambiguity:
public static void DoSomething<TKey, TListValue>(this Dictionary<TKey, List<TListValue>> dictionary)
{
...
}
You can use it without specifying the type parameters. They should be infered:
Dictionary<string, List<string>> u = new Dictionary<string, List<string>>();
u.DoSomething();
Here is a sample implementation of the method that you want to write:
static class DictExtensions {
public static void Insert<TKey,TVal>(this IDictionary<TKey,List<TVal>> d, TKey k, TVal v) {
List<TVal> current;
if (!d.TryGetValue(k, out current)) {
d.Add(k, new List<TVal> { v } );
} else {
current.Add(v);
}
}
}
The name Add would collide with the instance method of Dictionary, so I used the name Insert.
Demo.
Rather than an extension method, I would personally create a class inheriting from Dictionary:
public class ListDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
new public List<TValue> this[TKey index]
{
get
{
List<TValue> list = null;
if (!TryGetValue(index, out list))
{
list = new List<TValue>();
Add(index, list);
}
return list;
}
set
{
if (ContainsKey(index))
base[index] = value;
else
Add(index, value);
}
}
}
Usage:
ListDictionary<string, string> dictionary = new ListDictionary<string, string>();
dictionary["list1"].Add("item1"); // list will be initialised here
dictionary["list1"].Add("item2");
dictionary["list2"].Add("item1"); // and another

What is the best type to hold an ordered pair of values of the same type in C#?

What is the best type to hold an ordered pair of values of the same type in C#?
By that I'd want that:
Two values composition is enforced at compile-time (no possibility of trying to add or remove at compile- or run-time).
Two values have the same static type.
Two values can be retrieved using an indexer (e.g. pair[0], pair[1]).
UPDATE: I changed my mind, I don't really want #3 anymore since it pointlessly opens the door to out of bound exceptions:
You could extend the Tuple class like this:
public class Pair<T> : Tuple<T, T>
{
public Pair<T>(T item1, T item2) : base(item1, item2)
{
}
public T this[int index]
{
get
{
if (index == 0)
return Item1;
else if (index == 1)
return Item2;
throw new ArgumentOutOfRangeException("index");
}
}
}
Edit: Added constructor.
Apart from not having an indexer, Tuple<T1, T2> seems to match your needs.
Tuple<int, int> myPair = Tuple.Create(1, 2);
int firstValue = myPair.Item1; // instead of myPair[0]
int secondValue = myPair.Item2; // instead of myPair[1]
Of course, nothing prevents you from subclassing MyPair<T> : Tuple<T, T> and adding an indexer, if this is a requirement.
You could create a List of tuples like this :
var data = new List<Tuple<string, string>>();
data.Add(new Tuple<string, string>("string1","string2"));
Tuple<string, string> record = data[0];
Edit : in case you want it to be readonly :
public static readonly List<Tuple<string, string>> data = new List<Tuple<string, string>>
{
new Tuple<string, string>("string1", "string2"),
new Tuple<string, string>("set2", "set2b")
};
How about a plain array of 2 elements?
Arrays are fixed-size, so elements cannot be added or removed.
All elements are of the same compile-time type.
You can use the indexer.
The disadvantage is that arrays of different sizes look the same to the type system, so you can't, for example, declare a function that receives only T[2] but not T[3]. If that's a problem, use noah1989's solution.

How to insert element in first index in dictionary?

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.

looking for an appropriate data structure(preferably Dictionary and List) for this scenario

In a method call an object is getting passed it.
From this object I can get two things: an ItemData propery and a Row property so for example:
oPTL.ItemData, oPTL.Row
I want to have a data structure that each time this method is called it can update this data structure so for example one time oPTL.ItemData is "Spread1" and oPTL.Row is 2 so we should be able to save that Spread1 has value 2...next call for example we should be able to save "Spread3" has value 3..next call "Spread1" has ALSO value 4 , etc...
So it is like a Dictionary<String,<List>> but still I have problem with declaring and using it this way in the code, any code sample you can help me with?
You can use a dictionary where the values are Lists:
IDictionary<string, List<int>> rows = new Dictionary<string, List<int>>();
To populate it you can use this extension method:
public static class DictionaryDefaultExtension
{
public static TValue GetOrDefault<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
Func<TValue> defaultValue)
{
TValue result;
if (dictionary.TryGetValue(key, out result))
{
return result;
}
else
{
TValue value = defaultValue();
dictionary[key] = value;
return value;
}
}
}
Use like this:
d.GetOrDefault(oPTL.ItemData, () => new List<int>()).Add(oPTL.Row);
What you're looking for is Dictionary<string, List<int>> - assuming your .ItemData and .Row properties are in fact string and int respectively.
When you read item with "Spread1" value, you first check whether such key already exists in dictionary by calling .ContainsKey(string) method. If so, you add new Row value - if not, you create new key with brand new list, like in example below:
var myItems = new Dictionary<string, List<int>>();
// ...
if (myItems.ContainsKey(newItem.ItemData))
{
// myItems[newItem.ItemData] actually contains List<int> we created at some
// point in the other part of if-else.
// The .Add method we call here belongs to List
List<int> itemValues = myItems[newItem.ItemData];
itemValues.Add(newItem.Row);
}
else
{
myItems.Add(newItem.ItemData, new List<int> { newItem.Row });
}
Edited to add clarification with two .Add methods.

Is there a Dictionary<string, object> collection which allows multiple keys?

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 ?

Categories

Resources