This question already has answers here:
Recreating a Dictionary from an IEnumerable<KeyValuePair<>>
(2 answers)
Closed last year.
I was following the answer to another question, and I got:
// itemCounter is a Dictionary<string, int>, and I only want to keep
// key/value pairs with the top maxAllowed values
if (itemCounter.Count > maxAllowed) {
IEnumerable<KeyValuePair<string, int>> sortedDict =
from entry in itemCounter orderby entry.Value descending select entry;
sortedDict = sortedDict.Take(maxAllowed);
itemCounter = sortedDict.ToDictionary<string, int>(/* what do I do here? */);
}
Visual Studio's asking for a parameter Func<string, int> keySelector. I tried following a few semi-relevant examples I've found online and put in k => k.Key, but that gives a compiler error:
'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string,int>>'
does not contain a definition for 'ToDictionary' and the best
extension method overload
'System.Linq.Enumerable.ToDictionary<TSource,TKey>(System.Collections.Generic.IEnumerable<TSource>,
System.Func<TSource,TKey>)' has some invalid arguments
You are specifying incorrect generic arguments. You are saying that TSource is string, when in reality it is a KeyValuePair.
This one is correct:
sortedDict.ToDictionary<KeyValuePair<string, int>, string, int>(pair => pair.Key, pair => pair.Value);
with short version being:
sortedDict.ToDictionary(pair => pair.Key, pair => pair.Value);
I believe the cleanest way of doing both together: sorting the dictionary and converting it back to a dictionary would be:
itemCounter = itemCounter.OrderBy(i => i.Value).ToDictionary(i => i.Key, i => i.Value);
The question is too old but still would like to give answer for reference:
itemCounter = itemCounter.Take(maxAllowed).OrderByDescending(i => i.Value).ToDictionary(i => i.Key, i => i.Value);
Related
So I have A dictionary (Employees2Name) Of int => (some class) which I need to turn into a sorted list of key value pairs of int => (some property in the class)
I have this working fine which is the good news. It just seems like I'm doing an extra step is there a way to shorten this in linq with a cast.
ComboBoxValues.Employees2Name.Select(k => new {Key = k.Key, Value = k.Value.Name})
.ToDictionary(k => k.Key, v => v.Value)
.ToList<KeyValuePair<int, string>>()
.OrderBy(kp => kp.Value)
The second to dictionary seems redundant.
It seems that all you need is
ComboBoxValues.Employees2Name
.Select(k => new KeyValuePair<int, string>(k.Key, k.Value.Name))
.OrderBy(item => item.Value);
Just Select and OrderBy; try no to materialize (i.e. ToList(), ToDictionary()) especially in the middle of the Linq.
#Servy Comments reflects the best answer.
Your already have this in an
IEnumberable<KeyPairValue<int, Class>> you just need to put the name to a dictionary then order by
#Html.PopulateCombobox(ComboBoxValues.Employees2Name
.ToDictionary(k => k, v => v.Value.Name)
.OrderBy(v => v.Value)
Dictionary class already implements IEnumerable>, that is a valid input for your OrderBy() then applying a ToList>() seems totally useless.
More, I think that the ToDictionary call is a waste of memory and time, because you are constructing the dictionary (which main purpose is to keep items unique by key) from a plain collection of items and later sort them by value (rather than key), thus without taking any advantage from the Dictionary<,> class.
I would rewrite your code as
ComboBoxValues.Employees2Name.Select(k => new KeyValuePair<int, string>(k.Key, k.Value.Name))
.OrderBy(kp => kp.Value)
Regards,
Daniele.
No need to use select and orderby. You can just try this
SortedList<int, string> sortedList =
new SortedList<int, string>(ComboBoxValues.Employees2Name
.ToDictionary(i => i.Key, i => i.Value.Name));
I have a Dictionary<string, string> and another List<string>. What I am trying to achieve is a linq query to get all items out of the dictionary where any values from said dictionary are in the List<string>.
I found this post to be helpful, LINQ querying a Dictionary against a List . And was able to write the following linq expression, however my results never actually return anything.
What I have so far.
Data is the dictionary and PersonList is the list of strings.
var Persons = PersonList.Where(x => Data.ContainsKey(x))
.Select(z => new { key = z, value = Data[z] })
.ToList();
Are you looking for keys or values? If you're looking for values use
var Persons = Data.Where(kvp => PersonList.Contains(kvp.Value))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
If instead you really want keys then your code should work but another option would be:
var Persons = Data.Where(kvp => PersonList.Contains(kvp.Key))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
Try this one:
var Persons = Data.Where(x=>PersonList.Contains(x.Value))
.Select(x=>new { key=x.Key, value=x.Value})
.ToList();
I converted the result to a list, because I noticed that you used it in your code. If you want it to a dictionary, just take a look to the answer provided by D Stanley.
I think you don't have to convert it ToDictionary, because your source is a dictionary:
var Persons = Data.Where(kvp => personList.Contains(kvp.Key))
.Select(x => x);
I quickly tested it in LinqPad, but if this is a bad idea or I'm wrong, please leave a comment.
This is my list
List<KeyValuePair<string, int>> lstRodsMonsterPool = new List<KeyValuePair<string, int>>();
Now i am trying to sort it like this but it is giving error
lstRodsMonsterPool = (from entry in lstRodsMonsterPool
orderby entry.Value ascending
select entry)
.ToList<new KeyValuePair<string,int>(pair => pair.Key, pair => pair.Value)>;
C# 4.0
Thank you
.ToList() doesn't take parameters.
lstRodsMonsterPool = lstRodsMonsterPool.OrderBy(x => x.Value).ToList();
It looks like you're trying to sort the list in place, so you can use the Comparison<T> overload of List.Sort:
lstRodsMonsterPool.Sort((l,r) => l.Value.CompareTo(r.Value))
How to convert in the shortest way a list of Tuples to Dictionary (C#) ?
IList<Tuple<long, int>> applyOnTree = getTuples();
Assuming the long is the key and the int is the value;
applyOnTree.ToDictionary(x => x.Item1, x => x.Item2);
Obviously, just reverse those two if it's the other way around.
Use ToDictionary extension method:
var dictionary = applyOnTree.ToDictionary(l => l.Item1, l => l.Item2);
I have a generic Dictionary where TValue is of type String (Dictionary<int, string>). I chose to use string as the value type because the data was loaded from an Xml file where the source values can be character or numeric data types (I suppose Object would've been an acceptable TValue type too, but even then this question would be equally applicable).
The character data types also have importance, so excluding them outright isn't an option.
I'd like to extract a subset of this Dictionary<int, double>. In other words, I'd like the subset of the dictionary where the values are numeric.
Right now I'm doing it like this:
Dictionary<int, string> myDictionary;
// Do some loading.
var numericData = myDictionary.Where(kvp => Double.TryParse(kvp.Value, out temp)
This approach is awfully ugly and doesn't get me the result as a Dictionary<int, double> Can anyone offer other ways to improve this?
Thanks!
The code you've given is not only ugly - it will fail with an InvalidCastException at execution time. I suspect you actually want:
var numericData = myDictionary
.Select(kvp => {
double value;
return new { kvp.Key,
Value = double.TryParse(kvp.Value, out value)
? value : (double?) null
};
})
.Where(pair => pair.Value != null)
.ToDictionary(pair => pair.Key, pair => pair.Value.Value);
And yes, that's ugly - but:
It avoids parsing the value more than once
It avoids putting side-effects in your query
You can make it slightly cleaner but less efficient if you're happy to parse twice:
var numericData = myDictionary
.Where(kvp => { double tmp; return double.TryParse(kvp.Value, out tmp); })
.ToDictionary(pair => pair.Key, pair => double.Parse(pair.Value));
Or (more cleanly) you could create a separate method:
public static double? TryParseNullableDouble(string text)
{
double value;
return double.TryParse(text, out value) ? value : (double?) null;
}
Then the first version becomes:
var numericData = myDictionary
.Select(kvp => new { kvp.Key, TryParseNullableDouble(kvp.Value) })
.Where(pair => pair.Value != null)
.ToDictionary(pair => pair.Key, pair => pair.Value.Value);
You can just create a new dictionary using the temp variable which contains the double value - this exploits the fact that the enumeration and addition to the dictionary is done item by item so temp contains the correct double value:
double temp = 0;
var numDict = myDictionary.Where(kvp => Double.TryParse(kvp.Value, out temp))
.ToDictionary( x=> x.Key, x=> temp);