c# associative array with dictionary - c#

I want to build an Dictonary like this :
Dictionary<String, ArrayList> myDic = new Dictionary<String, ArrayList>();
in the end i want a structure like :
["blabla"] => array(1,2,3)
["foo"] => array(1,4,6,8)
.......
to build this i run in a loop and in every loop build some strings ,
first question :
how to check every time if this string exists
in the dictionary , if its not exists open a new entry in dictionary with one element in the array list, if exists only add another element to the array list
and another question:
how can i sort this dictionary according to number of elements in the array list(In descending order) like :
["foo"] => array(1,4,6,2,8)
["bar"] => array(4,6,2,8)
["bla"] => array(1,2,3)
["blo"] => array(1,2)
.......
thanks !

Use the right tool for the job. The data structure you want is called a "multi-dictionary" - that is a dictionary that maps from a key to a sequence of values, rather than from a key to a unique value.
The PowerCollections codebase contains an implementation of MultiDictionary that probably does what you want. I would use it rather than writing your own.
To sort the dictionary into a sequence of key/sequence pairs ordered by the length of the sequence, I would use a LINQ query with an "order by" clause. That seems like the easiest way to do it.

Instead of ArrayList you should use an array or List<T>. Assuming you have a Dictionary<string, int> called source this should work:
var items = source
.GroupBy(kvp => kvp.Key)
.Select(grp => new { Key = grp.Key, Items = grp.Select(kvp => kvp.Value).ToArray() })
.OrderByDescending(i => i.Items.Length);
To explain, Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>> so can be considered a sequence of key-value pairs. Group by groups the pairs by key and then Select creates a sequence of an anonymous type which contains the key and associated values in a Key and Items property respectively. This sequence is then ordered by the number of items in the Items array of each object.
If you want to order them by the length of the created array, you can't use a dictionary since they are not ordered.

To check if a key exists in a dictionary and use the value if it does, you can use TryGetValue:
ArrayList array;
if(!myDic.TryGetValue("blabla", out array))
{
array = new ArrayList();
myDic["blabla"] = array;
}
array.Add(42);

Would something like this work:
if (myDic.ContainsKey(myString))
myDic[myString].Add(myNumber);
else
myDic.Add(myString, new ArrayList(new int[] {myNumber}));

Related

How to get Distinct keys of all child dictionary elements of all parent dictionary values

I have a dictionary like this...
Dictionary<string, Dictionary<string, double>>
How to get the list of all Distinct or unique child dictionary keys from all dictionaries of all parent dictionary values (parent dictionary values is nothing but child dictionaries)?
which is the fastest way of doing this in C#?
It's really easy using LINQ:
var result = myDict.Values.SelectMany(x => x.Keys)
.Concat(myDict.Keys)
.Distinct()
.ToList();
but even without LINQ it's super easy when you use HashSet<string>:
var set = new HashSet<string>();
foreach(var outerItem in myDict)
{
set.Add(outerItem.Key);
foreach(var innerKey in item.Value.Keys)
{
set.Add(innerKey);
}
}
HashSet<T> will only keep distinct items, so adding the same string twice won't make any difference.
PS. Next time you should try writing the code first, and ask question when you run into issue you can't overcome by yourself. Stack Overflow is not 'I want code, give me code' kind of site.
Then you need to call SelectMany() on Values property of your dictionary and then use Distinct() to get distinct elements from a sequence by using the default equality comparer.
var res = myDict.Values.SelectMany(x => x.Keys).Distinct().ToList();
This code creates a Dictionary with string keys and double values.
Dictionary<string, double> d = new Dictionary<string, double>()
{
};
// Store keys in a List
List<string> list = new List<string>(d.Keys);
// Loop through list
foreach (string k in list)
{
//From here you can choose distinct key
}
If I'm reading this right:
IEnumerable<string> uniqueChildKeys = dictOfDicts
.SelectMany(d => d.Value.Keys)
.Distinct();

Add element to a tuple outside of initialization c#

I'm new to programming, and I created a tuple list with
var tupleList = new List<Tuple<string, string>> { };
Later on in the code, I'd like to add an element like
tupleList.Add(string1,string2);
but .Add doesn't support this somehow?
Basically, I'm going through a loop and adding to the tuple and later I want to search through the tuple for a sample string, so my second question is how would I search through tupleList.Item1 and get all the pairs that equal, for example string10? I saw an answer for dictionary values, but can I do the same for tuples?
var matches = tupleList.Where(pair => pair.Item1.Equals(string10))
.Select(pair => Item2.Key);
I don't know if that makes sense though, this was the original code:
var matches = dict.Where(pair => pair.Value == "abc")
.Select(pair => pair.Key);
List<T> does not have any specific methods for working with tuples. It works with any type T. If you want to add new item to list, you should create item of list's type T and pass it to list. Adding new tuple:
tupleList.Add(Tuple.Create(string1,string2));
For searching just filter tuples list. You should not project tuples with Select operator if you want to get them as result:
var matches = tupleList.Where(pair => pair.Item1 == string10);
NOTE: I don't like tuples for their meaningless names Item1, Item2 etc, which is hard to understand. Consider creating custom class which will have properties with descriptive names.
I'd say why do the same for tuples?
If you are using a tuple to represent a key value pair, just stick to a key value pair, which is what a dictionary contains a collection of. If you model a row with more than 2 values, I'd probably favour a strongly typed model over this, where you can be more explicit in your LINQ queries.

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);

How to compare the values in a Dictionary using Linq

I have a function that returns a Dictionary. Key = Players, Value = Score.
Now I want to compare the scores and create a new Dictionary with the new rearanged list where the top score is on top.
Whenever I use GroupBy, it creates automatically Dictionary
so if I do something like this
Dictionary<string, int> player = playersRank.getRoundRank ().GroupBy (v => v.Value).Select(k => k.Key);
I get a Dictionary<int, <string,int>>
How can I order them by value but get Dictionary in return?
Your result collection can not be a dictionary because a dictionary is not a ordered collection. You have some options, for example you could use a List of KeyValuePair
List<KeyValuePair<string, int>> sortedScores;
sortedScores = playersRank.getRoundRank().OrderByDescending(v => v.Value).ToList();
You could use many other types too (or even create your own class), it all depends on how you plan on using this list of sorted scores after you create it. If you update your question with more details we may be able to give you better answers on what type of collection you should use.

The order of elements in Dictionary

My question is about enumerating Dictionary elements
// Dictionary definition
private Dictionary<string, string> _Dictionary = new Dictionary<string, string>();
// add values using add
_Dictionary.Add("orange", "1");
_Dictionary.Add("apple", "4");
_Dictionary.Add("cucumber", "6");
// add values using []
_Dictionary["banana"] = 7;
_Dictionary["pineapple"] = 7;
// Now lets see how elements are returned by IEnumerator
foreach (KeyValuePair<string, string> kvp in _Dictionary)
{
Trace.Write(String.Format("{0}={1}", kvp.Key, kvp.Value));
}
In what order will be the elements enumerated? Can I force the order to be alphabetical?
The order of elements in a dictionary is non-deterministic. The notion of order simply is not defined for hashtables. So don't rely on enumerating in the same order as elements were added to the dictionary. That's not guaranteed.
Quote from the doc:
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey, TValue> structure representing a value and its key. The order in which the items are returned is undefined.
You can always use SortedDictionary for that. Note that the dictionary is ordered by Key, by default, unless a comparer has been specified.
I'm skeptic regarding the use of OrderedDictionary for what you want since documentation says that:
The elements of an OrderedDictionary are not sorted by the key, unlike
the elements of a SortedDictionary class.
If you want the elements ordered, use a SortedDictionary. An ordinary hastable/dictionary is ordered only in some sense of the storage layout.
The items will be returned in the order that they happen to be stored physically in the dictionary, which depends on the hash code and the order the items were added. Thus the order will seem random, and as implementations change, you should never depend on the order staying the same.
You can order the items when enumerating them:
foreach (KeyValuePair<string, string> kvp in _Dictionary.OrderBy(k => k.Value)) {
...
}
In framework 2.0 you would first have to put the items in a list in order to sort them:
List<KeyValuePair<string, string>> items = new List<KeyValuePair<string, string>>(_Dictionary);
items.Sort(delegate(KeyValuePair<string, string> x, KeyValuePair<string, string> y) { return x.Value.CompareTo(y.Value); });
foreach (KeyValuePair<string,string> kvp in items) {
...
}
For an OrderedDictionary:
var _OrderedDictionary = new System.Collections.Specialized.OrderedDictionary();
_OrderedDictionary.Add("testKey1", "testValue1");
_OrderedDictionary.Add("testKey2", "testValue2");
_OrderedDictionary.Add("testKey3", "testValue3");
var k = _OrderedDictionary.Keys.GetEnumerator();
var v = _OrderedDictionary.Values.GetEnumerator();
while (k.MoveNext() && v.MoveNext()) {
var key = k.Current; var value = v.Current;
}
Items are returned in the order that they are added.
Associative arrays (aka, hash tables) are unordered, which means that the elements can be ordered in any way imaginable.
HOWEVER, you could fetch the array keys (only the keys), order that alphabetically (via a sort function) and then work on that.
I cannot give you a C# sample because I don't know the language, but this should be enough for you to go on yourself.

Categories

Resources