I am trying to run this query but it gives me exception.
"At least one object must implement IComparable."
I don't want to order/distinct by my custom object but just by a string (v.Venue). However the similar query with a custom object (instead of string), that doesn't implement IComparable, works fine.
here is my query:
new ObservableCollection<KeyValuePair<int, string>>(
EventsList.Where(p => !string.IsNullOrEmpty(p.Venue))
.Distinct()
.OrderBy(i => i)
.Select((v, index) => new KeyValuePair<int, String>(index, v.Venue))
);
EventsList is an ObservableCollection<EventSchedules>
Also, I tried breaking the entire query into pieces, but it fails only for this last query:
Select((v, index) => new KeyValuePair<int, String>(index, v.Venue))
EventList object has to implement IComparable in order to execute Distinct() and OrderBy() functions. Linq needs to know how to compare instances of EventList in order to sort them and remove duplicates.
Comment answer:
You can order by and do distinct by p.Venue. I.e.:
new ObservableCollection<KeyValuePair<int, string>>(
EventsList.Where(p => !string.IsNullOrEmpty(p.Venue))
.GroupBy(p => p.Venue)
.Select(grp => grp.First()) // These two lines are lambda way to say Distinct.
.OrderBy(p => p.Venue)
.Select((v, index) => new KeyValuePair<int, String>(index, v.Venue))
);
Or you can implement a custom comparer.
As per LINQ basics ,
If you are using EventList you have to implement Icomparable to use distinct and Orderby.
I am sure your Query is breaking at OrderbY line but it is shows at Next Line
I solved it after analyzing my query, I didn't want to sort on my Custom Object (EventSchedule) as others suggested. What I wanted to order & distinct is an string. So I rearranged my query as:
new ObservableCollection<KeyValuePair<int, string>>(
EventsList.Where(p => !string.IsNullOrEmpty(p.Venue))
.Select(p => p.Venue) //added this
.Distinct()
.OrderBy(i => i)
.Select((v, index) => new KeyValuePair<int, String>(index, v))
);
Related
I have List<Dictionary<DateTime, Points[]>> taskResult generated from tasks
var taskResult = tasks.Select(t => t.Result).ToList();
var data = new Dictionary<DateTime, Points[]>();
in my function I want to return Dictionary<DateTime, Points[]> data but I cant figure out how to do that. I tried using foreach but had no luck
Enumerable.SelectMany extension method is right tool for the job, which combines many collections into one. Dictionary is a collection of key-value pairs.
var combined = dictionaries
.SelectMany(dictionary => dictionary.Select(pair => pair))
.GroupBy(pair => pair.Key)
.ToDictionary(
group => group.Key,
group => group.SelectMany(pair => pair.Value).ToArray());
Approach above will merge points of same date if original dictionaries contain duplicated dates
Because Dictionary implements IEnumerable you can remove .Select in first call of SelectMany.
Alternative for .GroupBy is .ToLookup method, which can have multiple values per one key.
var combined = dictionaries
.SelectMany(dictionary => dictionary)
.ToLookup(pair => pair.Key, pair.Value)
.ToDictionary(
lookup => lookup.Key,
lookup => lookup.SelectMany(points => points).ToArray());
So I come with a List list and first make it to a dictionary for faster searches.
Dictionary<Guid, Int32> dictionaryFromList = list
.ToDictionary(x => x.Item1, y => y.Item2);
Now Im loading all the other info in another Dictionary from the cache:
Dictionary<Guid, Model> modelDictionary = _cache
.Where(x => dictionaryFromList.ContainsKey(x.Id))
.Select(y => new {y.Id, y })
.ToDictionary(t => t.Id, t=> t.y);
Now I need two different things:
1. I need to insert more data into some of the Models in the modelDictionary
2. I need to insert the Int32 from the dictionaryFromList into the modelDictionary
My approach for 1. was the following:
HashSet<Guid> toLoadIds = new HashSet<Guid>(modelDictionary
.Where(x => !x.Value.IsLoaded)
.Select(x => x.Key));
context.myTable
.Where(x => toLoadIds.Contains(x.Id))
.Select(x => new {x.value1, x.value2, x.value3, x.value4, x.value5, x.value6 }));
I selected the values now afaik but how should I get them into the right model in the modelDictionary?
For the 2. one I tried doing this:
dictionaryFromList.Select(y => modelDictionary[y.Key].myValue = y.Value);
But it seems like nothing is working properly :(
The previous solution for the 2. was the following when modelDictionary was stil a List
modelDictionary.ForEach(x => x.myValue = dictionaryFromList[x.AddressId]);
When you write:
dictionaryFromList.Select(y => modelDictionary[y.Key].myValue = y.Value);
the execution is deferred until someone runs through the returned select iterator. But you do not pick it up, so no-one does that.
You could do:
dictionaryFromList.Select(y => modelDictionary[y.Key].myValue = y.Value)
.LastOrDefault();
where the final call will force the iteration of the select iterator. But I find that ugly. Why not simply use foreach?
foreach (var y in dictionaryFromList) { modelDictionary[y.Key].myValue = y.Value; }
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'm trying to do a GroupBy and then OrderBy to a list I have. Here is my code so far:
reportList.GroupBy(x => x.Type).ToDictionary(y=>y.Key, z=>z.OrderBy(a=>a.Lost));
With the help of the last question I asked on linq I think the ToDictionary is probably unneeded, but without it I don't know how to access the inner value.
To be clear, I need to GroupBy the Type property and want the inner groups I get to be OrderBy the Lost property (an integer). I want to know if there is a better, more efficient way or at the least better then what I've done.
An explanation and not just an answer would be very much appreciated.
Yes, there is better approach. Do not use random names (x,y,z,a) for variables:
reportList.GroupBy(r => r.Type)
.ToDictionary(g => g.Key, g => g.OrderBy(r => r.Lost));
You can even use long names to make code more descriptive (depends on context in which you are creating query)
reportList.GroupBy(report => report.Type)
.ToDictionary(group => group.Key,
group => group.OrderBy(report => report.Lost));
Your code does basically the following things:
Group elements by type
Convert the GroupBy result into a dictionary where the values of the dictionary are IEnumerables coming from a call to OrderBy
As far as the code correctness it is perfectly fine IMO, but maybe can be improved in term of efficiency (even if depends on your needs).
In fact, with your code, the values of your dictionary are lazily evaluated each time you enumerate them, resulting in a call to OrderBy method.
Probably you could perform it once and store the result in this way:
var dict = reportList
.GroupBy(x => x.Type)
.ToDictionary(y => y.Key, z => z.OrderBy(a => a.Lost).ToList());
// note the ToList call
or in this way:
var dict = reportList.OrderBy(a => a.Lost)
.GroupBy(x => x.Type)
.ToDictionary(y => y.Key, z => z);
// here we order then we group,
// since GroupBy guarantees to preserve the original order
Looks fine to me. If you use an anonymous type instead of a Dictionary, you could probably improve the readability of the code that uses the results of this query.
reportList.GroupBy(r => r.Type)
.Select(g => new { Type = g.Key, Reports = g.OrderBy(r => r.Lost) });
Is there any way in LINQ to do an OrderBy and then do a ThenBy with the ThenBy using the children of the parent object to do the secondary ordering?
_repository.GetActiveDepartmentGroupsWithDepartments().OrderBy(c => c.DepartmentGroupName).ThenBy(c => c.Departments.OrderBy(d => d.DepartmentName))
In the above case, c.Departments is an EntityCollection.
BTW: When I try the above and then do a ToList() on it, I get this error:
DbSortClause expressions must have a type that is order comparable.
Parameter name: key
Thanks in advance for any help or guidance.
It seems like you're trying to get a list of all departments ordered by group then department name. If so, then you probably want to do something like this:
var res = from c in _repository.GetActiveDepartmentGroupsWithDepartments()
from d in c.Departments
orderby c.DepartmentGroupName, d.DepartmentName
select d;
Or in method syntax:
var res = _repository.GetActiveDepartmentGroupsWithDepartments()
.SelectMany(c => c.Departments, (c,d) => new { c, d })
.OrderBy(x => x.c.DepartmentGroupName)
.ThenBy(x => x.d.DepartmentName)
.Select(x => x.d);
Since Deparment is a collection, you have to transform it to a scalar to use it for sorting.
One option is to select a single entity to in the collection, e.g. the name of the first department:
_repository.GetActiveDepartmentGroupsWithDepartments()
.OrderBy(c => c.DepartmentGroupName)
.ThenBy(c => c.Departments
.OrderBy(d => d.DepartmentName)
.FirstOrDefault()
.DepartmentName
)
Another option is to order by a property of the collection itself, e.g. the number of departments:
_repository.GetActiveDepartmentGroupsWithDepartments()
.OrderBy(c => c.DepartmentGroupName)
.ThenBy(c => c.Departments.Count())