Sort Dictionary (string, int) by value - c#

So basically I'm having an issue with the task I've been given. I won't bore you with the details of the task itself so I'll just give you the relevant info.
I have a dictionary that I need to be sorted by the int[value] that is the highest, well the top five highest to be precise and I need to be able to show the bottom five as well.
Dictionary<string, int> dict = new Dictionary<string, int>();
The strings(keys) hold words that have been read for a text file. The ints (values) hold ints of how many times they were mentioned in the document.
I was going to do it in another way but I was told to do it with a dictionary so please dictionary only help.
I would appreciate it if you can explain how it should be done so I can learn as well as complete the task as the aim of the task is to educate myself but I'm finding it a bit hard..
I appreciate all your help in advance, if more info is required please let me know and I'll post it!

Dictionaries do not have any inherent order. But if you want to get the top 5 entries with highest (or lowest) values, you can use a little Linq:
using System.Linq;
...
var top5 = dict.OrderByDescending(pair => pair.Value).Take(5);
var bottom5 = dict.OrderBy(pair => pair.Value).Take(5);
This will return an IEnumerable<KeyValuePair<string, int>>. To turn it back into a dictionary, again Linq can help. For example:
var top5 = dict.OrderByDescending(pair => pair.Value).Take(5)
.ToDictionary(pair => pair.Key, pair => pair.Value);
Now, top5 is a Dictionary<string, int> which contains only the 5 elements from dict with the hightest value.

You need to get ordered result from your dictionary, Since you are looking for Top 5, you will need Take like:
//Top 5
foreach (var item in dict.OrderByDescending(r => r.Value).Take(5))
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
The reason you need an OrderBy is because:
Dictionary<TKey, TValue> Class
For purposes of enumeration, each item in the dictionary is treated as
a KeyValuePair structure representing a value and its
key. The order in which the items are returned is undefined.

If you are using C# 3.0 and higher
You can do something like this with LINQ
foreach (KeyValuePair<string,int> item in keywordCounts.OrderBy(key=> key.Value).Take(5))
{
// do something with item.Key and item.Value
}
If you are using C# 2.0
List<KeyValuePair<string, string>> myList = aDictionary.ToList();
myList.Sort((firstPair,nextPair) =>
{
return firstPair.Value.CompareTo(nextPair.Value);
}
);
or it can be rewritten as
myList.Sort((x,y)=>x.Value.CompareTo(y.Value));
LINQ allows for great flexibility in that you can select the top 10, 20 10% etc. Or if you are using your word frequency index for type-ahead, you could also include StartsWith clause as well.

Related

Create dictionary outside and initialize it using LINQ

I have dictionary indices and want to add several keys to it from another dictionary using LINQ.
var indices = new Dictionary<string, int>();
var source = new Dictionary<string, int> { { "1", 1 }, { "2", 2 } };
source.Select(name => indices[name.Key] = 0); // doesn't work
var res = indices.Count; // returns 0
Then I replace Select with Min and everything works as expected, LINQ creates new keys in my dictionary.
source.Min(name => indices[name.Key] = 0); // works!!!
var res = indices.Count; // returns 2
Question
All I want to do is to initialize dictionary without foreach. Why dictionary keys disappear when LINQ is executed? What iterator or aggregator I could use instead of Min to create keys for a dictionary declared outside of LINQ query?
Update #1
Decided to go with System.Interactive extension.
Update #2
I appreciate and upvote all answers, but need to clarify that, purpose of the question is not to copy a dictionary, but to execute some code in a LINQ query. To add more sense to it, I actually have hierarchical structure of classes with dictionaries and at some point they need to be synchronized, so I want to create flat, non-hierarchical dictionary, used for tracking, that includes all hierarchical keys.
class Account
{
Dictionary<string, User> Users;
}
class User
{
Dictionary<string, Activity> Activities;
}
class Activity
{
string Name;
DateTime Time;
}
Now I want to sync all actions by time, so I need a tracker that will help me to align all actions by time, and I don't want to create 3 loops for Account, User, and Activity. Because that would be considered a hierarchical hell of loops, the same as async or callback hell. With LINQ I don't have to create loop inside loop, inside loop, etc.
Accounts.ForEach(
account => account.Value.Users.ForEach(
user => user.Value.Activities.ForEach(
activity => indices[account.Key + user.Key + activity.Key] = 0));
Also, having loops where it can be replaced with LINQ can be considered as a code smell, not my opinion, but I totally agree, because having too many loops you will probably end up in duplicated code.
https://jasonneylon.wordpress.com/2010/02/23/refactoring-to-linq-part-1-death-to-the-foreach/
You can say that LINQ is used for querying, not for setting a variable, I would say I'm querying ... the KEYS.
Linq is not intended to be used to mutate the elements of a sequence. Rather, it is intended to be used to traverse, filter and project elements of a sequence. In this respect, it is intended to be used more in a "functional programming" style.
As you have discovered, Linq can be used in other than a functional programming style - but by using it in that way you are really misusing it.
Technically, the reason that source.Min() has the effect you were looking for is that it has to visit each of the elements of your sequence in order to determine the minimum element.
Because your selector for Min() has a side-effect (i.e. indices[name.Key] = 0) then a side-effect of finding the minimum value is to add each element's key to indices, but with a value of zero rather than the original value.
(I suspect you might have meant to put indices[name.Key] = name.Value...)
The reason that your use of Select() has no effect is that it has not been used to traverse the sequence - it uses "deferred execution".
You can force it to traverse the sequence by counting the elements, like so:
source.Select(name => indices[name.Key] = 0).Count();
However, that is also counter-intuitive and is a misuse of Linq.
The correct solution is to use foreach. This expresses your intent clearly and unambiguously.
An alternative approach is to write an AddRange() extension method for Dictionary like so:
public static class DictionaryExt
{
public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(
this Dictionary<TKey, TValue> self,
IEnumerable<KeyValuePair<TKey, TValue>> items)
{
foreach (var item in items)
{
self[item.Key] = item.Value;
}
return self;
}
}
Then you can just call indices.AddRange(source); to achieve your aim.
Interestingly, the ImmutableDictionary type does already have an AddRange() method that you could use like so:
var indices = ImmutableDictionary.Create<string, int>();
var source = new Dictionary<string, int> { { "1", 1 }, { "2", 2 } };
indices = indices.AddRange(source);
Console.WriteLine(indices.Count);
But I wouldn't recommend you change over to using ImmutableDictionary just so you can use its AddRange().
Also note that ImmutableDictionary is, well, immutable - so you can't just do indices.AddRange(source);; you have to assign the result back as in indices = indices.AddRange(source); (like when you modify a string using ToUpper()).
You wrote:
All I want to do is to initialize dictionary without foreach
Do you want to replace the values in your indices dictionary with the values in source? Use Enumerable.ToDictionary
indices = (KeyValuePair<string, int>)source // regard the items in the dictionary as KeyValuePairs
.ToDictionary(pair => pair.Key, // the key is the key from original dictionary
pair => pair.Value); // the value is the value from the original
Or do you want to add the values from source to the already existing values in indices? If you don't want a foreach you'll have to take the current values from both dictionaries and Concat them to the values from source. Then use the ToDictionary to create a new Dictionary.
indices = (KeyValuePair<string, int>) indices
.Concat(KeyValuePair<string, int>) source)
.ToDictionary(... etc)
However this would be a waste of processing power.
Consider creating extension functions for Dictionary. See Extension Methods Demystified
public static Dictionary<TKey, TValue> Copy>Tkey, TValue>(
this Dictionary<TKey, TValue> source)
{
return source.ToDictionary(x => x.Key, x => x.Value);
}
public static void AddRange<TKey, TValue>(
this Dictionary<TKey, TValue> destination,
Dictionary<TKey, TValue> source)
{
foreach (var keyValuePair in source)
{
destination.Add(keyValuePair.Key, keyValuePair.Value);
// TODO: decide what to do if Key already in Destination
}
}
Usage:
// initialize:
var indices = source.Copy();
// add values:
indices.AddRange(otherDictionary);

How to turn a dictionary<string, int> elements into strings. c#

I'm currently working on a game in which the top 5 highscores can be displayed on a highscores page.
Currently i have a dictionary of type [string, int] which will store the user's name and score respectively.However, i'm having trouble creating a method that will take all 5 dictionary elements in the format of {"name", 20} and assign each element to a string.
For example, dictionary element[0] contains the value {sam, 20}. I would like to assign this element to a string that would read "sam 20".
At the moment i have a method which will return the top5 highscores but my problem occurs when turning these values into strings from dictionary elements.
Any help would be appreciated and if you have any questions, please don't hesitate to ask.
Thanks in advance.
You can use .Select() and string interpolation to build out a projected string list:
var formattedStrings = dict
.OrderByDescending(x => x.Value)
.Select(x => $"{x.Key} {x.Value}").ToList();
Since Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>, we can easily use LINQ to both order and project our key/value pairs before interpolating them into a new string.
This also allows for more flexible querying before projecting your list.
try this.
var answer= string.Join(",", map.Select(s => s.Key + " " +s.Value).ToArray());

Aggregating/Merging a number of concurrent dictionaries

So I have a concurrent dictionary defined as such
ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, SomeObject>>>();
I know that seems a little convoluted but the structure is valid...
Now my problem is that I have say x number of instances of these dictionaries for x different sources and for statistical purposes they need to be merged/amalgamated/aggregated into one single dictionary of the same structure...
Anyone any ideas on the best approach? I know I could create a new dictionary of the same structure; loop through each of the dictionaries to be amalgamated and at each level checking the new dictionary for those keys etc and adding or updating based on the result of that determination...
But that seems slightly unwieldy to me... any LINQ geniuses out there that could lend a hand?
[Note - I just made one important edit - the output dictionary is of the exact same structure as the input dictionaries]
LINQ doesn't help here, as you don't want to query a collection but manipulate one.
As said in the comments above, using a ConcurrentDictionary<Tuple<string, string, string>, SomeObject> would simplify things a bit. You could do the following then:
using MyDict = ConcurrentDictionary<Tuple<string, string, string>, SomeObject>;
MyDict Merge(IEnumerable<MyDict> dicts)
{
MyDict result = new MyDict();
foreach (var dict in dicts)
{
foreach (var kvp in dict)
{
result.AddOrUpdate(
kvp.Key, // If the key does not exist, add the value;
kvp.Value, // otherwise, combine the two values.
(key, value) => Combine(value, kvp.Value)
);
}
}
return result;
}

Linq: Except on two different types of dictionaries

i have 2 different types of dictionaries Dictionary<int, Fooclass> oldDic and Dictionary<int, string> barList newDic . Now i need to compare values in both dictionaries. for Example key can be in
oldDic : 1,2,3
newDic : 1,2,3,4
Expected Output : 4
Now i need to compare both dictionaries on basis of their keys
any help would be appreciated.
Edit :
Output should be like second dictionary(newDic) but this will contain some value of 2nd dictionary's(oldDic). For example
1,"fooString" Where fooString is some value in Fooclass's someproperty....
For more clarity see this which doesn't worked for me
var addedList = from list1 in baseListDic
join list2 in trackerlist on list1.Key equals list2.Key
select new { key = list1.Key, value = list1.Value._lead };
here baseListDic is oldDic and trackerlist is newDic....
Let me know if i'm still not clear...
It would be easier to just create a new dictionary based on the new dictionary ignoring items that have the same key in the old dictionary.
var result = newDic
.Where(kvp => !oldDic.ContainsKey(kvp.Key))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
Note: Despite your question saying "i need to compare values in both dictionaries" (emphasis mine) your example seems to be demonstrating just comparison of keys so I've gone with that. If it is values you need to compare you might want to give an example of what you mean and if they are easily convertible or comparable...
If you are only actually comparing the keys then you can just use the .Keys property of the dictionary which returns an IEnumerable<TKey> that you can do your linq on...
eg:
var expectedOutput = newDic.Keys.Except(oldDic.Keys);
This does rely on the key being the same type but this goes without saying if you are comparing. Of course, there is nothing stopping you from converting their types first if you do wnat to do this with different types.
Also if you wanted to then get the values in one of the dictionaries you could do something like:
var newDicValues = expectedoutput.Select(x=>newDic[x]);
Or, you know, do any other linqy stuff you feel like. :)
Try this to get the difference between two different list: If they have any common property.
var differentItems = List<Type1>.Select(d => d.Name)
.Except(List<Type2>.Select(d => d.Name));
If understood correctly, try something like this
if you have a separate dictionary moething like this Dictionary<int, Fooclass> FinalDict
IEnumerable<int> list = OldDic.Keys.Except(NewDic.Keys);
foreach (var x in list)
{
var value =new MyClass();
OldDic.TryGetValue(x,out value );
FinalDict.Add(x,value);
}
So in the Dictionary called FinalDict will have the key and related Fooclass
Hope this helps

Get index of a key/value pair in a C# dictionary based on the value

I would like to know if some property or method exists that gets the index of a specific value.
I found that dictionaries have the Contains() method which returns true if the value passed in exists, so this method almost implements what I need.
I know that I can loop through all the value pairs and check the condition, but I ask because maybe there's an optimized way of doing this.
Let's say you have a Dictionary called fooDictionary
fooDictionary.Values.ToList().IndexOf(someValue);
Values.ToList()
converts your dictionary values into a List of someValue objects.
IndexOf(someValue)
searches your new List looking for the someValue object in question
and returns the Index which would match the index of the Key/Value pair in the dictionary.
This method does not care about the dictionary keys, it simply returns the index of the value that you are looking for.
This does not however account for the issue that there may be several matching "someValue" objects.
There's no such concept of an "index" within a dictionary - it's fundamentally unordered. Of course when you iterate over it you'll get the items in some order, but that order isn't guaranteed and can change over time (particularly if you add or remove entries).
Obviously you can get the key from a KeyValuePair just by using the Key property, so that will let you use the indexer of the dictionary:
var pair = ...;
var value = dictionary[pair.Key];
Assert.AreEqual(value, pair.Value);
You haven't really said what you're trying to do. If you're trying to find some key which corresponds to a particular value, you could use:
var key = dictionary.Where(pair => pair.Value == desiredValue)
.Select(pair => pair.Key)
.FirstOrDefault();
key will be null if the entry doesn't exist.
This is assuming that the key type is a reference type... if it's a value type you'll need to do things slightly differently.
Of course, if you really want to look up values by key, you should consider using another dictionary which maps the other way round in addition to your existing dictionary.
Consider using System.Collections.Specialized.OrderedDictionary, though it is not generic, or implement your own (example).
OrderedDictionary does not support IndexOf, but it's easy to implement:
public static class OrderedDictionaryExtensions
{
public static int IndexOf(this OrderedDictionary dictionary, object value)
{
for(int i = 0; i < dictionary.Count; ++i)
{
if(dictionary[i] == value) return i;
}
return -1;
}
}
You can find index by key/values in dictionary
Dictionary<string, string> myDictionary = new Dictionary<string, string>();
myDictionary.Add("a", "x");
myDictionary.Add("b", "y");
int i = Array.IndexOf(myDictionary.Keys.ToArray(), "a");
int j = Array.IndexOf(myDictionary.Values.ToArray(), "y");
You can use LINQ to help you with this.
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "hi");
dict.Add(2, "NotHi");
dict.Add(3, "Bah");
var item = (from d in dict
where d.Value == "hi"
select d.Key).FirstOrDefault();
Console.WriteLine(item); //Prints 1
If searching for a value, you will have to loop through all the data. But to minimize code involved, you can use LINQ.
Example:
Given Dictionary defined as following:
Dictionary<Int32, String> dict;
You can use following code :
// Search for all keys with given value
Int32[] keys = dict.Where(kvp => kvp.Value.Equals("SomeValue")).Select(kvp => kvp.Key).ToArray();
// Search for first key with given value
Int32 key = dict.First(kvp => kvp.Value.Equals("SomeValue")).Key;
In your comment to max's answer, you say that what you really wanted to get is the key in, and not the index of, the KeyValuePair that contains a certain value. You could edit your question to make it more clear.
It is worth pointing out (EricM has touched upon this in his answer) that a value might appear more than once in the dictionary, in which case one would have to think which key he would like to get: e.g. the first that comes up, the last, all of them?
If you are sure that each key has a unique value, you could have another dictionary, with the values from the first acting as keys and the previous keys acting as values. Otherwise, this second dictionary idea (suggested by Jon Skeet) will not work, as you would again have to think which of all the possible keys to use as value in the new dictionary.
If you were asking about the index, though, EricM's answer would be OK. Then you could get the KeyValuePair in question by using:
yourDictionary.ElementAt(theIndexYouFound);
provided that you do not add/remove things in yourDictionary.
PS: I know it's been almost 7 years now, but what the heck. I thought it best to formulate my answer as addressing the OP, but of course by now one can say it is an answer for just about anyone else but the OP. Fully aware of that, thank you.
no , there is nothing similar IndexOf for Dictionary although you can make use of ContainsKey method to get whether a key belongs to dictionary or not

Categories