Any Dictionary that can handle dupes? - c#

I am parsing a test file, in for form of:
[Person]: [Name]-[John Doe], [Age]-[113], [Favorite Color]-[Red].
[Person]: [Name]-[John Smith], [Age]-[123], [Favorite Color]-[Blue].
[Person]: [Name]-[John Sandles], [Age]-[133], [Favorite Color]-[Green].
[Person]: [Name]-[Joe Blogs], [Age]-[143], [Favorite Color]-[Khaki].
As you can see, the values are not duplicated (though I want to account for future dupes), but the Keys are dupes. The keys being the parts before the hyphen (-).
But everytime I get these into a Dictionary it has a fit and tells me dupes aren't allowed. Why doesn't the Dictionary allow dupes? And how can I overcome this?

The Dictionary has the TKey part of it being hashed for fast lookup, if you have dupes in there, you'll get into collisions and complexities, which will reduce your ability to look things up quickly and efficiently. That is why dupes are not allowed.
You could make a struct with the data in it, and put that in a Dictionnary<ID, MyStruct> for example. This way you avoid dupes in the key (which is unique for each struct, and you have all your data in a Dictionary.

Dictionary can have dupes in value but cannot have dupes in Key because then how will you tell which key's value do you want.
And how can I overcome this
use a KeyvaluePair[] but in that case also how will you tell which key's value do you want?

You can use the Wintellect Power Collections' MultiDictionary class. Power Collections is a long-established set of collection classes for .Net 2 or later. It hasn't been updated for 5 years, but it doesn't need to be.
See here: http://powercollections.codeplex.com/
Download it here: http://powercollections.codeplex.com/releases/view/6863

The simplest thing to do is to use an Dictionary<string, List<string>>.
Usage:
foreach(var person in persons)
{
List<string> list;
if(!dict.TryGetValue(person.Key, out list)
{
list = new List<string>();
dict.Add(person.Key, list);
}
list.Add(person.Data);
}

Lookup<TKey, TElement> class from System.Linq namespace represents a collection of keys each mapped to one or more values. More info: MSDN
List<Person> list= new List<Person>();
// ...
var lookup = list.ToLookup(person => person.Key, person => new {Age=person.Age, Color=person.Color});
IEnumerable<Person> peopleWithKeyX = lookup["X"];
public class Person
{
public string Key { get; set; }
public string Age { get; set; }
public string Color { get; set; }
}

Based on your question I suppose that you are using [Name], [Age] and [Favorite Color] as keys. There are many ways how to put your data into the dictionary using these keys, but the real question is how will you get it back?
The keys in Dictionary should be unique, so you need to find some unique data to use it as a key.
In your case the test file looks like list of Persons, where each line contains person's data. So the most natural way is to compose a dictionary that contains rows about persons where 'unique data' should be a Person's name, unless it is not duplicated.
In real life however Person's name is usually a bad choice, (not only because it may change over time, but also because the probability of identical names is very high), so artificial keys are used instead (row number, Guids, etc.)
Edit I see that number of properties may vary. So you need to use nested dictionaries. Outer - for 'Persons' and inner for Person properties:
Dictionary<string, Dictionary<string, string>> person_property_value;
However for your data structure to be more understandable you should put the inner dictionary inside Person class:
class Person{
public readonly Dictionary<string, string> props;
public Person()
{
props = new Dictionary<string, string>();
}
}
Now you add the Person as:
Person p = new Person();
p.props['Name'] = 'John Doe';
p.props['Age'] = 'age';
dictionary.Add('John Doe', p);
And get it back as:
Person p = dictionary[Name];
Now to allow several persons share the same name you declare the dictionary as Dictionary<string, List<Person>>

Related

How to use Linq and lambda expressions on a Dictionary<string, List<T>> to a specify its order based on Key

So I have a Dictionary with string keys, and the value is a List of objects. Each object in each List has a property value which is equal to that List's associated key. In other words, the Dictionary is grouping objects by property value via the key. For example, let's say we have,
Dictionary<string, List<Animal>> GroupedByClass = new Dictionary<string, Animal>();
Where Animal is an object which contains a string property named "ClassType" which has valid options of "Mammal", "Reptile", or "Amphibian", etc.
The Animal class could also have string property named "Species" which more uniquely defines each object in the Dictionary.
A pseudocode description of the contents of the Dictionary could be:
<"Mammal", List<Animal>>
where the Animals in the list have Species "Dog", "Cat"
<"Reptile", List>
where the Animals in the list have Species "Snake", "Lizard", and "Turtle"
<"Amphibian", List>
where the Animals in the list have Species "Salamander" and "Frog"
I want to rearrange this Dictionary by the key value such that the values with a key of "Reptile" are first, then "Amphibian", and then finally "Mammal". Note that I do not want to sort this based on alphabetical order, I want to specify my own order.
I know I could solve this problem by simply iterating through the Dictionary a few times, extracting only the items with the right key. For example, I could do it like this,
Dictionary<string, List<Animal>> temp = new Dictionary<string, List<Animal>>();
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Reptile")
{
temp.Add(item.Key, item.Value);
}
}
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Amphibian")
{
temp.Add(item.Key, item.Value);
}
}
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Mammal")
{
temp.Add(item.Key, item.Value);
}
}
return temp;
However, this seems inelegant, and I was wondering if there was a better answer for this problem using Linq queries and lambda expressions.
This should be close (with some syntax errors):
var order = new [] {"Reptile","Amphibian","Mammal"};
var elems = dict.OrderBy(x=>order.IndexOf(x.Key));
if you want to flatten the results, then you can use SelectMany:
var order = new [] {"Reptile","Amphibian","Mammal"};
var elems = dict.SelectMany(x=>x).OrderBy(x=>order.IndexOf(x.Species));
Dictionary<string, List<Animal>> temp = new Dictionary<string,List<Animal>>();
(new List<string>() {"Reptile","Amphibian","Mammal"}).ForEach(x => temp.Add(x, GroupedByClass[x]));
You could define an enumeration and have it be your defining order.
enum Animal : int
{
Reptile = 0,
Amphibian = 1,
Mammal = 2
}
Note, since you have simple strings this works and is straight forward. If however you end up with strings that have spaces you can use the DescriptionAttribute of the enumeration and go between it and the actual enumeration.
Enumeration with Display String
By using an enumeration over the string you can do many things, but of course order by it using the integers you assiged.

C# - Array Infrastructure in a Class using Controls

I am just curious whether or not this can be achieved: I have currently got a sort of problem where I am using controllers to set and get data inside a Class and this is done through methods and instances on the handler side.
I am just wondering, because doing public string x { get; set; } can become very long winded for each property that your project consists of.
Is there a way that I can achieve this sort of ideology inside a Class?
public core Array[] (
Option1 => string Array[] (
Name => 'example'
),
Option2 => String Array[] (
Name => 'example2'
) { set; get; }
);
Of course, this is just a theory and won't be the exact solution. I am wondering if I'd:
1) Need a controller when appending data to the index's.
2) Need to instance the Class that the Controller handles or if I can do it through Main Class methods.
3) Need a multidimensional Array or List.
My current solution is to long winded and due to the large amount of Data the Core site uses, It's response is descending for every feature being added.
Could anyone reference any infrastructure references or possibly give a walk through on how to actually allocate the properties using this ideology?
Thank-you in advance.
Edit: I mean something like this (PHP):
$example = array (
'location1' => array(
'location_id' => 1
),
'location2' => array(
'location_id' => 2
)
);
Now the data can be handled easier by:
foreach($example as $k=>$v){ // todo: handle }
So here $k becomes your array name (ie it could be, Name, Address) and $v becomes your nested array making data so much easier to handle.
While I strongly disagree with the usage of this pattern, I still think it's valuable to know.
I think you are looking for a Dictionary<TKey, TValue>. It provides a way to map keys of any type to values of any type. For your use case:
IDictionary<string, string> DynamicProperties {get; set;} = new Dictionary<string, string>
{
{ "FirstName", "John" },
{ "LastName", "Doe" }
};
You can then iterate over your "properties" with a loop:
foreach(KeyValuePair pair in DynamicProperties)
{
string key = pair.Key; // "FirstName", "LastName"
string value = pair.Value; // "John", "Doe"
// Use them as you wish.
}
You can have dictionaries of dictionaries too. To match your updated example:
IDictionary<string, IDictionary<string, int>> Example {get; set;} = new Dictionary<string, IDictionary<string, int>>
{
{"location1", new Dictionary<string, int> {{"location_id", 1}}},
{"location2", new Dictionary<string, int> {{"location_id", 2}}}
};
But look at this code - you were looking for simplicity. This is not simple at all, nor is it short, clear, or testable. Having classes and properties is the way to go in C#.
I think the root of the problem here is that you are coding with C#, but thinking with PHP ideas. C# is strongly typed, while PHP is weakly typed, (see this wiki article), and you need to readjust your thinking appropriately.
I suggest to look how ViewBag used in MVC works
here a good link
How ViewBag in ASP.NET MVC works

How can I check for string values in a Dictionary<string, List<string[]>>() object?

To keep it simple, I have the following Dictionary that I fill with an unknown amount of strings for every string key. I also have the following list of strings.
var dict = new Dictionary<string, List<string[]>>();
IList<string> headerList = new List<string>();
How can I check if a string from the list is a value in the dictionary?
My data looks like similar to this:
Key Value
----- ------------------
Car honda, volks, benz
Truck chevy, ford
I need to check if "honda", for example, is a contained int the dictionary values. I am thinking I need to do something like the following to see if the values contain a list, which contain the string in question. Keep in mind I am fairly new to C#.
foreach (string header in headerList)
{
// This is wrong, I don't know what to put in the if statement
if (dict.ContainsValue(r => r.Contains(header)))
{
// do stuff
}
}
John Odom is correct, you need a List.
What I would suggest is that you use a HashSet<string> internally for the value of the Diictionary. E.g. Dictionary<string, HashSet<string>>
Then when it comes to querying it you can do something like this:
headerList.Where(x => dict.Values.Any(d => d.Contains(x))).ToList()
Have a look at .NET Nested Loops vs Hash Lookups for a performance comparison
If you only want to know if the dictionary contains the car bran (e.g. "honda") you can use this query:
bool isInDict = dict.Values
.SelectMany(lst => lst)
.Any(car => car == "honda");
To return the key under which the value is stored you can use something like this:
string containingKey = dict.Keys
.Where(key => dict[key].Contains("honda"))
.FirstOrDefault();
And to get the whole list in which the value occurs run this:
List<string> containingList = dict.Values
.Where(v => v.Contains("honda"))
.FirstOrDefault();
In the first case all you do you flatten all the lists and check them all if any value is the searched car name. If true the value is in the dictionary.
Second one: get all the keys. Apply each key to the dictionary to get respective list and check the list if it contains the car name. Return the first key under which the car name has been found.
Third one - similar to the second one, but we run the search on the values. Check if the value (i.e. List) contains the car name. Return the first collection that does contain the name.

Sorting a dictionary by keys in the order in an Arraylist

I was asked the following question in an interview. How can I sort a Dictionary by the key, in the order which is in an array list.
So for example I have a dictionary as follows
Dictionary<string, string> stringDict = new Dictionary<string, string>();
stringDict.Add("1", "One");
stringDict.Add("7", "Seven");
stringDict.Add("6", "Six");
stringDict.Add("2", "Two");
stringDict.Add("3", "Three");
stringDict.Add("5", "Five");
stringDict.Add("4", "Four");
And an array list as follows
ArrayList stringArList = new ArrayList();
stringArList.Add("1");
stringArList.Add("2");
stringArList.Add("3");
stringArList.Add("5");
stringArList.Add("6");
stringArList.Add("7");
stringArList.Add("4");
How can I sort the dictionary in the order it is in the array list?
Well you can't sort a Dictionary per se, but you can extract the key-values pairs as a list and sort those:
IEnumerable<KeyValuePair<string, string>> pairs =
stringDict.OrderBy(kvp => stringArList.IndexOf(kvp.Key));
But there's not a way to "traverse" dictionary items in any particular order.
You could create a SortedDictionary and provide an IComparer<string>
var d = new SortedDictionary<string, string>(stringDict,
new PositionComparer(stringArList));
With the Comparer implementation as:
public class PositionComparer : IComparer<string>
{
private ArrayList Keys {get; set;}
public PositionComparer(ArrayList keys)
{
Keys = keys;
}
public int Compare(string s1, string s2)
{
return Keys.IndexOf(s1).CompareTo(Keys.IndexOf(s2));
}
}
This will produce a list of the values sorted as required.
var sortedValues = stringDict.OrderBy(pair => stringArList.IndexOf(pair.Key))
.Select(pair => pair.Value)
.ToList();
As said many times before in this question, a C# Dictionary can not be sorted. This is inherent to the implementation. As you can read here, the dictionary is implemented using a Hashtable. This means that those items don't have any ordering. You can't say "give me the first element of this dictionary". There simply is no first, second or last element. The only thing you can say about an element in a dictionary is that it has a unique identifier which determines it's location in the dictionary (with a little help from the hash function).
When you have an element in an array for example, you can say "this element is the next element" or "this element is the previous element". Each element in an array has a previous and a next. This does not hold for dictionaries.
When you insert an item into the dictionary it will generate a hash (a fairly unique number) based on the key. For example, a very simple (and bad) hash of keys consisting of names would be to take the sum of each character presented as their ASCII value in the name, and then add those together. The result is a number, say 5, then we would insert the value in a store (an array for example) on position 5. If however, at position 5 is another value, which happens to have the same hash result you have a collision. How you solve these, and how you avoid these is what hashtables are all about. See the Wiki for more information on this.
When you request your value with your key someName it will hash that value and look it up at that position.
Hashtables are not as easy as I just explained, there is a lot too it. You can read more on the Wiki.
So the answer to "Sort this dictionary" is most definitely "No can do.". However, you can convert it to a sortable data structure like a list, or whatever and then sort it.
I replied with the following answer.
var list = from arElement in stringArList.ToArray().ToList()
join dict in stringDict on arElement equals dict.Key
select dict ;
But the interviewer didn't seem to be impressed.
original_dic.OrderBy returns IOrderedEnumerable, that you convert to a new dictionary.
var ordered_dic = original_dic.OrderBy(x => x.Key).ToDictionary(x=> x.Key, x=> x.Value);

Accessing a Dictionary.Keys Key through a numeric index

I'm using a Dictionary<string, int> where the int is a count of the key.
Now, I need to access the last-inserted Key inside the Dictionary, but I do not know the name of it. The obvious attempt:
int LastCount = mydict[mydict.keys[mydict.keys.Count]];
does not work, because Dictionary.Keys does not implement a []-indexer.
I just wonder if there is any similar class? I thought about using a Stack, but that only stores a string. I could now create my own struct and then use a Stack<MyStruct>, but I wonder if there is another alternative, essentially a Dictionary that implements an []-indexer on the Keys?
As #Falanwe points out in a comment, doing something like this is incorrect:
int LastCount = mydict.Keys.ElementAt(mydict.Count -1);
You should not depend on the order of keys in a Dictionary. If you need ordering, you should use an OrderedDictionary, as suggested in this answer. The other answers on this page are interesting as well.
You can use an OrderedDictionary.
Represents a collection of key/value
pairs that are accessible by the key
or index.
A Dictionary is a Hash Table, so you have no idea the order of insertion!
If you want to know the last inserted key I would suggest extending the Dictionary to include a LastKeyInserted value.
E.g.:
public MyDictionary<K, T> : IDictionary<K, T>
{
private IDictionary<K, T> _InnerDictionary;
public K LastInsertedKey { get; set; }
public MyDictionary()
{
_InnerDictionary = new Dictionary<K, T>();
}
#region Implementation of IDictionary
public void Add(KeyValuePair<K, T> item)
{
_InnerDictionary.Add(item);
LastInsertedKey = item.Key;
}
public void Add(K key, T value)
{
_InnerDictionary.Add(key, value);
LastInsertedKey = key;
}
.... rest of IDictionary methods
#endregion
}
You will run into problems however when you use .Remove() so to overcome this you will have to keep an ordered list of the keys inserted.
Why don't you just extend the dictionary class to add in a last key inserted property. Something like the following maybe?
public class ExtendedDictionary : Dictionary<string, int>
{
private int lastKeyInserted = -1;
public int LastKeyInserted
{
get { return lastKeyInserted; }
set { lastKeyInserted = value; }
}
public void AddNew(string s, int i)
{
lastKeyInserted = i;
base.Add(s, i);
}
}
You could always do this:
string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]
But I wouldn't recommend it. There's no guarantee that the last inserted key will be at the end of the array. The ordering for Keys on MSDN is unspecified, and subject to change. In my very brief test, it does seem to be in order of insertion, but you'd be better off building in proper bookkeeping like a stack--as you suggest (though I don't see the need of a struct based on your other statements)--or single variable cache if you just need to know the latest key.
I think you can do something like this, the syntax might be wrong, havent used C# in a while
To get the last item
Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();
or use Max instead of Last to get the max value, I dont know which one fits your code better.
I agree with the second part of Patrick's answer. Even if in some tests it seems to keep insertion order, the documentation (and normal behavior for dictionaries and hashes) explicitly states the ordering is unspecified.
You're just asking for trouble depending on the ordering of the keys. Add your own bookkeeping (as Patrick said, just a single variable for the last added key) to be sure. Also, don't be tempted by all the methods such as Last and Max on the dictionary as those are probably in relation to the key comparator (I'm not sure about that).
In case you decide to use dangerous code that is subject to breakage, this extension function will fetch a key from a Dictionary<K,V> according to its internal indexing (which for Mono and .NET currently appears to be in the same order as you get by enumerating the Keys property).
It is much preferable to use Linq: dict.Keys.ElementAt(i), but that function will iterate O(N); the following is O(1) but with a reflection performance penalty.
using System;
using System.Collections.Generic;
using System.Reflection;
public static class Extensions
{
public static TKey KeyByIndex<TKey,TValue>(this Dictionary<TKey, TValue> dict, int idx)
{
Type type = typeof(Dictionary<TKey, TValue>);
FieldInfo info = type.GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance);
if (info != null)
{
// .NET
Object element = ((Array)info.GetValue(dict)).GetValue(idx);
return (TKey)element.GetType().GetField("key", BindingFlags.Public | BindingFlags.Instance).GetValue(element);
}
// Mono:
info = type.GetField("keySlots", BindingFlags.NonPublic | BindingFlags.Instance);
return (TKey)((Array)info.GetValue(dict)).GetValue(idx);
}
};
One alternative would be a KeyedCollection if the key is embedded in the value.
Just create a basic implementation in a sealed class to use.
So to replace Dictionary<string, int> (which isn't a very good example as there isn't a clear key for a int).
private sealed class IntDictionary : KeyedCollection<string, int>
{
protected override string GetKeyForItem(int item)
{
// The example works better when the value contains the key. It falls down a bit for a dictionary of ints.
return item.ToString();
}
}
KeyedCollection<string, int> intCollection = new ClassThatContainsSealedImplementation.IntDictionary();
intCollection.Add(7);
int valueByIndex = intCollection[0];
The way you worded the question leads me to believe that the int in the Dictionary contains the item's "position" on the Dictionary. Judging from the assertion that the keys aren't stored in the order that they're added, if this is correct, that would mean that keys.Count (or .Count - 1, if you're using zero-based) should still always be the number of the last-entered key?
If that's correct, is there any reason you can't instead use Dictionary<int, string> so that you can use mydict[ mydict.Keys.Count ]?
I don't know if this would work because I'm pretty sure that the keys aren't stored in the order they are added, but you could cast the KeysCollection to a List and then get the last key in the list... but it would be worth having a look.
The only other thing I can think of is to store the keys in a lookup list and add the keys to the list before you add them to the dictionary... it's not pretty tho.
To expand on Daniels post and his comments regarding the key, since the key is embedded within the value anyway, you could resort to using a KeyValuePair<TKey, TValue> as the value. The main reasoning for this is that, in general, the Key isn't necessarily directly derivable from the value.
Then it'd look like this:
public sealed class CustomDictionary<TKey, TValue>
: KeyedCollection<TKey, KeyValuePair<TKey, TValue>>
{
protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
{
return item.Key;
}
}
To use this as in the previous example, you'd do:
CustomDictionary<string, int> custDict = new CustomDictionary<string, int>();
custDict.Add(new KeyValuePair<string, int>("key", 7));
int valueByIndex = custDict[0].Value;
int valueByKey = custDict["key"].Value;
string keyByIndex = custDict[0].Key;
A dictionary may not be very intuitive for using index for reference but, you can have similar operations with an array of KeyValuePair:
ex.
KeyValuePair<string, string>[] filters;
You can also use SortedList and its Generic counterpart. These two classes and in Andrew Peters answer mentioned OrderedDictionary are dictionary classes in which items can be accessed by index (position) as well as by key. How to use these classes you can find: SortedList Class , SortedList Generic Class .
Visual Studio's UserVoice gives a link to generic OrderedDictionary implementation by dotmore.
But if you only need to get key/value pairs by index and don't need to get values by keys, you may use one simple trick. Declare some generic class (I called it ListArray) as follows:
class ListArray<T> : List<T[]> { }
You may also declare it with constructors:
class ListArray<T> : List<T[]>
{
public ListArray() : base() { }
public ListArray(int capacity) : base(capacity) { }
}
For example, you read some key/value pairs from a file and just want to store them in the order they were read so to get them later by index:
ListArray<string> settingsRead = new ListArray<string>();
using (var sr = new StreamReader(myFile))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string[] keyValueStrings = line.Split(separator);
for (int i = 0; i < keyValueStrings.Length; i++)
keyValueStrings[i] = keyValueStrings[i].Trim();
settingsRead.Add(keyValueStrings);
}
}
// Later you get your key/value strings simply by index
string[] myKeyValueStrings = settingsRead[index];
As you may have noticed, you can have not necessarily just pairs of key/value in your ListArray. The item arrays may be of any length, like in jagged array.

Categories

Resources