How can I shorten List<List<KeyValuePair<string, string>>>? - c#

I want to store an list of key value pair lists in a lightweight structure. This seems too cumbersome. What's better? Does List<Dictionary<string, string>> add much a overhead? What other options are available?

Consider using aliasing for shorthand:
namespace Application
{
using MyList = List<List<KeyValuePair<string, string>>>;
public class Sample
{
void Foo()
{
var list = new MyList();
}
}
}

Both List and Dictionary are pretty efficient, so I wouldn't think twice about using them. (Unless you're going to be storing a gazillion dictionaries in your list, but that's not very common.)
If you think that List<Dictionary<string, string>> is too much to type, you can say in your preamble
using LoDSS = System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, string>>;
Note that this is just an alias no subclassing needed.

Dictionary< string, string> and List< KeyValuePair< string, string>> could both be fine, depending on what data you wanted to pass around. Also, if you are going to use the same long type all over the place you could define the type somewhere else for a shorthand. Something like this:
public class MyShorthand : List<List<KeyValuePair<string, string>>> { }
Or you can use a using statement to define a type alias like this:
using MyShorthand = System.Collections.Generic.List<System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, string>>>;

If you are accessing the values by the key, use dictionary, that is what is meant for. To reduce the overhead of the dictionaries, try and give them an initial capacity.
Alternatively (if both lists are rather small), you could implement a custom hashing object, something like this (except prettier):
public class MyDictionary
{
private Dictionary<string, string> values;
public MyDictionary()
{
values = new Dictionary<string, string>();
}
public void Add(int index, string key, string value)
{
int hash = ((0xFFFF) & index) * (0xFFFF) + (0xFFFF) & key.GetHashCode();
values.Add(hash, value);
}
public string Get(int index, string key)
{
int hash = ((0xFFFF) & index) * (0xFFFF) + (0xFFFF) & key.GetHashCode();
return values[hash];
}
}

For clarity I would wrap your KeyValuePair<string, string> into something shorter, e.g. StringPair and also define a shorthand for a list of StringPair. This will shorten your syntax and help readability IMHO.
public class StringPair : KeyValuePair<string, string> { }
public class StringPairList : List<stringPair> { }
..
var jaggedList = new List<StringPairList>();

Related

Nested Dictionaries : Am I using the correct Data Structure [duplicate]

I have a structure that can be very easily represented using a three-deep nested dictionary, like so
private static Dictionary<string, Dictionary<string, Dictionary<string,string>>> PrerenderedTemplates;
Where the structure might be used something like this
PrerenderedTemplates[instanceID][templategroup][templatepart]
Now, I realise that this code is hard to read, because from looking at the definition statement, you can't tell what it's being used for. The only advantage I can really see in changing it to Dictionary<string, PrerenderedTemplate> is readability. Converting each nesting into its own class (e.g class PrerenderedTemplate{} class TemplateGroup{} class TemplatePart{}) would add many more lines of code for little (if any) computational advantage. As far as I can see.
So, is my approach "ok" or should I go the extra mile and create seperate classes?
Is it okay to cover how the nested Dictionary works in the documentation/comments
Is there a best practice for handling this sort of nesting?
Bear in mind, this is a private member, it doesn't need to be straightforward for people using the class.
Update
So, inspired by Reza, but unable to use Tuples, I decided to create my own key generator and implement his pattern like this:
private Dictionary<string, string> PrerenderedTemplates;
private string GetPrerenderedTemplateKey(string InstanceId, string FeatureId, string OptionId)
{
return new StringBuilder(instanceId)
.Append(FormatTools.LIST_ENTRY_DELIMITER)
.Append(templategroup)
.Append(FormatTools.LIST_ENTRY_DELIMITER)
.Append(templatepart).ToString();
}
Where FormatTools.LIST_ENTRY_DELIMITER is the Unicode Private Use Character 0xe04d.
I offer another choice:
Dictionary<Tuple<string, string, string>, string> pt;
Access to dictionary:
pt[Tuple.Create("id","group","part")]
UPDATE:
Value Tuples introduced in C# 7 is most eye-catching:
Dictionary<(string id, string group, string part), string> pt;
Access to dictionary:
pt[("id", "group", "part")]
I would create a custom dictionary. Something like this
public class TrippleKeyDict
{
private const string Separator = "<|>";
private Dictionary<string, string> _dict = new Dictionary<string, string>();
public string this[string key1, string key2, string key3]
{
get { return _dict[GetKey(key1, key2, key3)]; }
set { _dict[GetKey(key1, key2, key3)] = value; }
}
public void Add(string key1, string key2, string key3, string value)
{
_dict.Add(GetKey(key1, key2, key3), value);
}
public bool TryGetValue(string key1, string key2, string key3, out string result)
{
return _dict.TryGetValue(GetKey(key1, key2, key3), out result);
}
private static string GetKey(string key1, string key2, string key3)
{
return String.Concat(key1, Separator, key2, Separator, key3);
}
}
If you think, concatenating the strings is not safe enough, because the keys could contain the separators, then use your own key type or a Touple<string,string,string> as key. Since this implementation detail is hidden inside your custom dictionary, you can change it at any time.
You can use the dictionary like this
var dict = new TrippleKeyDict();
// Using the Add method
dict.Add(instanceID, templategroup, templatepart, "some value");
// Using the indexer
dict[instanceID, templategroup, templatepart] = "xy";
string result = dict[instanceID, templategroup, templatepart];
// Using the TryGetValue method
if (dict.TryGetValue(instanceID, templategroup, templatepart, out result)) {
// Do something with result
}
I would like to offer an alternative approach, using a SortedDictionary and a custom comparer:
public class PrerenderedTemplate
{
public string instanceID;
public string templategroup;
public string templatepart;
public PrerenderedTemplate(string id, string tempGroup, string tempPart)
{
instanceID = id;
templategroup = tempGroup;
templatepart = tempPart;
}
// custom comparer instance used as argument
// to SortedDictionary constructor
public class Comparer : IComparer<PrerenderedTemplate>
{
public int Compare(PrerenderedTemplate x, PrerenderedTemplate y)
{
int compare = 0;
if (compare == 0) compare = x.instanceID.CompareTo(y.instanceID);
if (compare == 0) compare = x.templategroup.CompareTo(y.templategroup);
if (compare == 0) compare = x.templatepart.CompareTo(y.templatepart);
return compare;
}
}
}
Is used like so:
var dictionary = new SortedDictionary<PrerenderedTemplate, string>(new PrerenderedTemplate.Comparer());
dictionary.Add(new PrerenderedTemplate("1", "2", "3"), "123");
dictionary.Add(new PrerenderedTemplate("4", "5", "6"), "456");
dictionary.Add(new PrerenderedTemplate("7", "8", "9"), "789");
Assert.AreEqual<string>(dictionary[new PrerenderedTemplate("7", "8", "9")], "789");
RezaArab's answer is fit for purpose but personally I dislike Tuples on the basis of their ambiguous properties and verbose syntax.
A custom class with comparer offers more clarity and also flexibility, should any requirements change.

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 do I create a Dictionary that holds different types in C#

I need some sort of way to store key/value pairs where the value can be of different types.
So I like to do:
int i = 12;
string s = "test";
double x = 24.1;
Storage.Add("age", i);
Storage.Add("name", s);
Storage.Add("bmi", x);
And later retrieve the values with:
int a = Storage.Get("age");
string b = Storage.Get("name");
double c = Storage.Get("bmi");
How should a Storage like this look like?
Thanks,
Erik
Well, you could use Dictionary<string, dynamic> in C# 4 / .NET 4 - but other than that, you can't do it with exactly the code shown because there's no type which is implicitly convertible to int, string and double. (You could write your own one, but you'd have to list each type separately.)
You could use Dictionary<string, object> but then you'd need to cast the results:
int a = (int) Storage.Get("age");
string b = (string) Storage.Get("name");
double c = (double) Storage.Get("bmi");
Alternatively, you could make the Get method generic:
int a = Storage.Get<int>("age");
// etc
You could declare a Dictionary containing just the type object and then cast your results; .e.g.
Dictionary<string, object> storage = new Dictionary<string,object>();
storage.Add("age", 12);
storage.Add("name", "test");
storage.Add("bmi", 24.1);
int a = (int)storage["age"];
string b = (string)storage["name"];
double c = (double)storage["bmi"];
However, this isn't that elegant. If you know you are always going to be storing age, name, bmi I would create an object to encapsulate those and store that instead. E.g.
public class PersonInfo
{
public int Age { get; set; }
public string Name { get; set; }
public double Bmi { get; set; }
}
And then use that insead of the Dictionary... e.g.
PersonInfo person1 = new PersonInfo { Name = "test", Age = 32, Bmi = 25.01 };
int age = person1.Age;
etc.
Why not use:
Dictionary<string, object>
You can create an extension method to cast them when you get them:
public static class DictionaryExcetions
{
public static T Get<T>(this Dictionary<string, object> instance, string name)
{
return (T)instance[name];
}
}
var age = dictionary.Get<int>("age");
Given that you don't want a strongly typed data collection then I would have thought a HashTable would be suitable for your situation. You could create an Extention method for this also, like another poster suggested for the Dictionary implementation.
E.g.
public static class StorageExtentions
{
public static T Get<T>(this Hashtable table, object key)
{
return (T) table[key];
}
}
Your code would then look like:
int i = 12;
string s = "test";
double x = 24.1;
Hashtable Storage = new Hashtable();
Storage.Add("age", i);
Storage.Add("name", s);
Storage.Add("bmi", x);
int a = Storage.Get<int>("age");
string b = Storage.Get<string>("name");
double c = Storage.Get<double>("bmi");
maybe it is an old question, but I am addressing the guys who come here to find the answer
if the value is not a fixed type one of the choices is using Hashtable
please look at the implementation of both Dictionary and Hashtable
public class Dictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IReadOnlyDictionary<TKey, TValue>, ICollection, IDictionary, IDeserializationCallback, ISerializable
{
...
}
public class Hashtable : ICollection, IEnumerable, IDictionary, ISerializable, IDeserializationCallback, ICloneable
{
...
}
as it gets more clear from above code snippets, both implement literally the same interfaces but in Hashtable there is no type on both key & value since both of them considered to be intrinsically objects, for example you can see from add method in Hashtable:
public virtual void Add(object key, object value);
so for the cases of not having fixed keys and/or values, I recommend using Hashtable, therefore you don't need to add extra extension methods or override default behavior of a dictionary any more.
Dictionary<string, object>
You can use a Dictionary<string,object> and then you can put anything you want into it. You would have to cast the results to the right type when you get them out though.
Looking at your example though you might want to consider whether a simple class to store the data might be more what you want and allow better type safety. It depends on whether you have a limited set of things to put in the class or if you do need the potentially unlimited/unknown storage of a dictionary.
Dictionary is clearly the quickest solution.
Another way could be to store a custom class in which you could store the actual value and the information regarding its type

What is the collection equivalent of a multi-dimensional array?

I've got a group of data that looks like this:
001 001 One
001 002 Two
001 003 Three
002 001 One
002 002 Two
002 003 Three
...
Now, certainly, I could create an array of string[x][y] = z, but this array has to be resizable, and i'd prefer to use the string representations of the indexers than convert to numeric. The reason is that i will need to look up the data by string, and i don't see the point in needless string->number conversions.
My first thought was this:
Dictionary<string, Dictionary<string, string>> data;
data = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> subdata = Dictionary<string, string>();
subdata.Add(key, string);
data.add(key2, subdata);
and this works, but is somewhat cumbersome. It also feels wrong and kludgy and not particularly efficient.
So what's the best way to store this sort of data in a collection?
I also thought of creating my own collection class, but I'd rather not if I don't have to. I'd rather just use the existing tools.
This is pretty common request, and most people end up writing some variation of a Tuple class. If you're using ASP.Net, you can utilize the Triple class that's already available, otherwise, write something like:
public class Tuple<T, T2, T3>
{
public Tuple(T first, T2 second, T3 third)
{
First = first;
Second = second;
Third = third;
}
public T First { get; set; }
public T2 Second { get; set; }
public T3 Third { get; set; }
}
There's a generic three-tuple class, so you can create a new List<Tuple<string, string, string>>() and create your tuples and add them. Expand on that basic class with some indexing functionality and you're up up and away.
Edit: A list with a dictionary doesn't seem like the correct approach, because each dictionary is only holding one value. There is no multi-entry relationship between the key and values - there is simply one multi-part key and one associated value. The data is equivalent to a database row (or tuple!).
Edit2: Here's an indexable list class you could use for convenience.
public class MyTupleList : List<Tuple<string, string, string>>
{
public Tuple<string, string, string> this[string first, string second]
{
get
{
return (this.Find(x => x.First == first && x.Second == second));
}
set
{
this[first, second] = value;
}
}
}
I think this really depends on what you are modelling here. If you're planning to use an object-oriented approach, you shouldn't be thinking of these as arbitrary items inside a data structure.
I'm guessing from looking at this that the first two columns are serving as a "key" for the other items. Define a simple struct, and create a dictionary of like so:
struct Key {
public int Val1 { get; set; }
public int Val2 { get; set; }
}
....
Dictionary<Key, string> values;
Obviously Key and the items inside it should be mapped to something closer to what you are representing.
Given a suitable Pair<A,B> class*, left as an exercise for the reader, you could use a Dictionary<Pair<string, string>, string>.
* A class with equality and hash code overrides, nothing terribly hard.
Would a List<List<T>> work for you? Still kludgy, but better than dictionaries IMHO.
EDIT: What about a Dictionary<string,string> and mapping the two keys to a single string?
var data = new Dictionary<string,string>(StringComparer.Ordinal);
data[GetKey("002", "001")] = "One";
with
string GetKey(string a, string b) {
return a + "\0" + b;
}
List<List<string>> is really your best bet in this case. But I agree, it's kludgy. Personally, I would create a custom class that implements a two-dimensional indexer and maybe use a List<List<T>> internally.
For example:
public class DynamicTwoDimensonalArray<T>
{
private List<List<T>> Items = new List<List<T>>();
public T this[int i1, int i2]
{
get
{
return Items[i1][i2];
}
set
{
Items[i1][i2] = value;
}
}
}
This is a basic idea to get you going; clearly the setter needs to deal with bounds issues. But it's a start.
Edit:
No. As I said, I would prefer to index them by string. And they may not always be sequential (might have a missing number in the middle). - Mystere Man
Hmm... this is interesting. If that's the case, your best bet would be to create some sort of concatenation of the combination of the two indexers and use that as the key in a single-level dictionary. I would still use a custom class to make using the indexing easier. For example:
public class TwoDimensionalDictionary
{
private Dictionary<string, string> Items = new Dictionary<string, string>();
public string this[string i1, string i2]
{
get
{
// insert null checks here
return Items[BuildKey(i1, i2)];
}
set
{
Items[BuildKey(i1, i2)] = value;
}
}
public string BuildKey(string i1, string i2)
{
return "I1: " + i1 + " I2: " + i2;
}
}
If you are ever going to need to find z by given (x,y) (and not, for example, find all y by given x), then use this:
Dictionary<KeyValuePair<string, string>, string>
Otherwise, your dictionary is fine as is.

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