Can somebody suggest me what Linq operator should I use to write an elegant code to convert List to Dictionary of list?
Eg. I have a list of person (List<Person>) and I wanted to convert that to dictionary of list (like Dictionary<string, List<Person>> using the person's last name as a key. I needed that for quickly lookup the list of persons by the last name
To get a Dictionary<string, List<Person>> from List<Person>:
var dictionary = list
.GroupBy(p => p.LastName)
.ToDictionary(g => g.Key, g => g.ToList());
This isn't what you asked for, but you can use Philip response for that :-)
var lookup = myList.ToLookup(p => p.Surname);
This will create an ILookup<string, Person> that is something very similar to what you wanted (you won't have a Dictionary<string, List<Person>> but something more similar to a Dictionary<string, IEnumerable<Person>> and and the ILookup is readonly)
you can also use as follows.
foreach(var item in MyList)
{
if(!myDictionary.Keys.Contains(item))
myDictionary.Add(item,item.value);
}
Related
I am trying to use Except to compare two list but one is an anonymous type.
For Example:
var list1 = customer.Select(x => new { x.ID, x.Name }).ToList();
var list2 = existcustomer.Select(x => x.ID).ToList();
And I trying to compare two list IDs and return a list of list one name.
My code:
var checkIfCustomerIdNotExist = list1.Where(x => x.ID.ToList().Except(list2)).Select(x => x.Name).ToList();
I am wondering if there is any workaround.
I'd advise using a dictionary instead of a List
//create a dictionary of ID to name
var customerDict = customer.ToDictionary(x => x.ID, x => x.Name);
//get your list to compare to
var list2 = existcustomer.Select(x => x.ID).ToList();
//get all entries where the id is not in the second list, and then grab the names
var newNames = customerDict.Where(x => !list2.Contains(x.Key)).Select(x => x.Value).ToList();
In general it's good to think about what data structure suits your data the best. In your case list1 contains a list of tuple where ID needs to be used to find Name - using a data structure more suited to that (A dictionary) makes solving your problem much easier and cleaner
Note, the solution assumes ID is unique, if there are duplicate IDs with different names you might need a Dictionary<string, List< string >> instead of just a Dictionary<string,string> - but that would probably require more than just a single line of linq, code would be fairly similar though
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.
I would like to take a list of objects and convert it to a dictionary where the key is a field in the object, and the value is a list of a different field in the objects that match on the key. I can do this now with a loop but I feel this should be able to be accomplished with linq and not having to write the loop. I was thinking a combination of GroupBy and ToDictionary but have been unsuccessful so far.
Here's how I'm doing it right now:
var samplesWithSpecificResult = new Dictionary<string, List<int>>();
foreach(var sample in sampleList)
{
List<int> sampleIDs = null;
if (samplesWithSpecificResult.TryGetValue(sample.ResultString, out sampleIDs))
{
sampleIDs.Add(sample.ID);
continue;
}
sampleIDs = new List<int>();
sampleIDs.Add(sample.ID);
samplesWithSpecificResult.Add(sample.ResultString, sampleIDs);
}
The farthest I can get with .GroupBy().ToDictionay() is Dictionary<sample.ResultString, List<sample>>.
Any help would be appreciated.
Try the following
var dictionary = sampleList
.GroupBy(x => x.ResultString, x => x.ID)
.ToDictionary(x => x.Key, x => x.ToList());
The GroupBy clause will group every Sample instance in the list by its ResultString member, but it will keep only the Id part of each sample. This means every element will be an IGrouping<string, int>.
The ToDictionary portion uses the Key of the IGrouping<string, int> as the dictionary Key. IGrouping<string, int> implements IEnumerable<int> and hence we can convert that collection of samples' Id to a List<int> with a call to ToList, which becomes the Value of the dictionary for that given Key.
Yeah, super simple. The key is that when you do a GroupBy on IEnumerable<T>, each "group" is an object that implements IEnumerable<T> as well (that's why I can say g.Select below, and I'm projecting the elements of the original sequence with a common key):
var dictionary =
sampleList.GroupBy(x => x.ResultString)
.ToDictionary(
g => g.Key,
g => g.Select(x => x.ID).ToList()
);
See, the result of sampleList.GroupBy(x => x.ResultString) is an IEnumerable<IGrouping<string, Sample>> and IGrouping<T, U> implements IEnumerable<U> so that every group is a sequence of Sample with the common key!
Dictionary<string, List<int>> resultDictionary =
(
from sample in sampleList
group sample.ID by sample.ResultString
).ToDictionary(g => g.Key, g => g.ToList());
You might want to consider using a Lookup instead of the Dictionary of Lists
ILookup<string, int> idLookup = sampleList.ToLookup(
sample => sample.ResultString,
sample => sample.ID
);
used thusly
foreach(IGrouping<string, int> group in idLookup)
{
string resultString = group.Key;
List<int> ids = group.ToList();
//do something with them.
}
//and
List<int> ids = idLookup[resultString].ToList();
var samplesWithSpecificResult =
sampleList.GroupBy(s => s.ResultString)
.ToDictionary(g => g.Key, g => g.Select(s => s.ID).ToList());
What we 're doing here is group the samples based on their ResultString -- this puts them into an IGrouping<string, Sample>. Then we project the collection of IGroupings to a dictionary, using the Key of each as the dictionary key and enumerating over each grouping (IGrouping<string, Sample> is also an IEnumerable<Sample>) to select the ID of each sample to make a list for the dictionary value.
While similar to this question which gave me the LINQ for part of my problem, I'm missing something that seems like it must be obvious to avoid the last step of looping through the dictionary.
I have a Dictionary and I want to get a List of keys for just the items for which the value is true. Right now I'm doing this:
Dictionary<long,bool> ItemChecklist;
...
var selectedValues = ItemChecklist.Where(item => item.Value).ToList();
List<long> values = new List<long>();
foreach (KeyValuePair<long,bool> kvp in selectedValues) {
values.Add(kvp.Key);
}
Is there any way I can go directly to a List<long> without doing that loop?
To do it in a single statement:
var values = ItemChecklist.Where(item => item.Value).Select(item => item.Key).ToList();
Try using Enumerable.Select:
List<long> result = ItemChecklist.Where(kvp => kvp.Value)
.Select(kvp => kvp.Key)
.ToList();