How to compare the values in a Dictionary using Linq - c#

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.

Related

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

sort Dictionary by generic value

I have tried to sort a Dictionary object by value which is generic.
Here is my code
Dictionary<string, ReportModel> sortedDic = new Dictionary<string, ReportModel>();
Dictionary<string, ReportModel> rDic = new Dictionary<string, ReportModel>();
var ordered = sortedDic.OrderByDescending(x => x.Value.totalPurchase);
foreach (var item in ordered)
{
rDic.Add(item.Key, item.Value);
}
The variable, ordered, just has the same order like sortedDic.
What is wrong with this?
Any idea?
This happens because Dictionary is generally an unordered container*. When you put the data into rDic, it becomes unordered again.
To retain the desired order, you need to put the results into a container that explicitly keeps the ordering that you supply. For example, you could use a list of KeyValuePair<string,ReportModel>, like this:
IList<KeyValuePair<string,ReportModel>> ordered = sortedDic
.OrderByDescending(x => x.Value.totalPurchase)
.ToList();
* Due to the way the Dictionary<K,V> is implemented by Microsoft, it happens to retain the insertion order, but that is incidental and undocumented, so it may change in the future versions, and should not be relied upon.
When adding the items back to the dictionary, it would not keep their order.
You can either:
Use the following implementation.
Use a list in the below form.
IEnumrable> lst=
sortedDic.OrderByDescending(x => x.Value.totalPurchase).ToArray();
[EDIT] If you don't mind the key changing then you can use SortedDictionary<,>.

Can Dictionary values be populated through a list without looping?

Can we have something like -
Dictionary<string, string> dict = new Dictionary<string, string>();
List<string> keysList= new List<string>();
List<string>valuesList= new List<string>();
//Assuming both the list have the same number of items
dict.keys = keysList;
dict.values = valuesList;
Mostly, I want to know if there is a way to populate the keys and values by directly assigning them to a list?
Mostly, I want to know if there is a way to populate the keys and values by directly assigning them to a list?
No, but just zip them and then use ToDictionary:
var dict = keysList.Zip(valuesList, (key, value) => Tuple.Create(key, value))
.ToDictionary(pair => pair.Item1, pair => pair.Item2);
A dictionary, internally isn't storing the data as two lists. It's storing the data in a hash table, which means it need to take each key, generate a hash for it, and then place the item at the location that corresponding to that hash. Because of this the only way to add a group of items is just to loop through the group and add each item. You can use the LINQ ToDictionary method, as mentioned in another answer, but internally all it's going to do is loop through each item and add it to the dictionary. This prevents you from seeing the loop, but the loop is still there.

c# associative array with dictionary

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

Categories

Resources