Are filter and sort commutative operations in database/linq query? - linq

For an arbitrary collection of objects, would following two LINQ expressions always give the same result (given that LINQ provider is the same):
var result = list.OrderBy(x => x.FirstName).Where(x => x.Age > 18);
var result = list.Where(x => x.Age > 18).OrderBy(x => x.FirstName);

While Enumerable<T>.OrderBy() is specified to be a stable sort, Queryable<T>.OrderBy() is not.
In other words, no, since the sort is not guaranteed to be stable, the two queries are not guaranteed to give the same result for all providers. At the very least, the results may be ordered in a different order.

Related

filtering a collection by its children in linq to entities?

I have the following query which filters the batches according to whether the items in the batches have a certain issue no. I would like to know if there is more concise way doing this which would look cleaner.
neptuneBatches =
neptuneBatches.Where(
b => b.Items.Any(
i => i.ItemOrganisations.Any(
s => s.Issues.Any(
x => x.Code == filter.IssueNo))));

preserving the order of returning entities when using .Contains(Id)

I want to hydrate a collection of entities by passing in a List of Ids and also preserve the order.
Another SO answer https://stackoverflow.com/a/15187081/1059911 suggested this approach to hydrating the entities which works great
var entities = db.MyEntities.Where(e => myListOfIds.Contains(e.ID)).ToList();
however the order of entities in the collection is different from the order of Ids
Is there a way to preserve the order?
May be that helps:
var entities = db.MyEntities
.Where(e => myListOfIds.Contains(e.ID))
.OrderBy(e => myListOfIds.IndexOf(e.ID)).ToList();
EDIT
JohnnyHK clarified that this will not work with LINQ to Entities. For this to work you need to order IEnumerable instead of IQueryable, since IQueryProvider don't know how to deal with local list IndexOf method when it sends query to server. But after AsEnumerable() OrderBy method deals with local data. So you can do this:
var entities = db.MyEntities
.Where(e => myListOfIds.Contains(e.ID))
.AsEnumerable()
.OrderBy(e => myListOfIds.IndexOf(e.ID)).ToList();
Entity Framework contains a subset of all of the LINQ commands so you won't have all the commands that LINQ to Objects has.
The following approach should give you your list of MyEntities in the same order as supplied by myListOfIds:
var entities = myListOfIds.Join(db.MyEntities, m => m, e => e.ID, (m,e) => e)
.ToList();

LINQ Order by question

I have a linq query that returns a list of employees and a job title.
I need to sort it by job title but have the ones that do not have any employees in the output list first.
Example sorted:
- Driver List{0}
- Attendant List{71}
- Pilot List{19}
The driver is first because it has nothing in the list and then it is sorted by title.
I am just curious what do you think would be my best option to accomplish that?
Thanks
Something like:
var query = employees.OrderBy(x => x.Subordinates.Any() ? 1 : 0)
.ThenBy(x => x.JobTitle);
You could also use the fact that false sorts earlier than true:
var query = employees.OrderBy(x => !x.Subordinates.Any())
.ThenBy(x => x.JobTitle);
... but that's a little bit less obvious, IMO.
Something like:
Jobs.OrderBy(j => j.Eployees.Count()).ThenBy(j => j.Name);

How do I merge two LINQ statements into one to perform a list2.Except(list1)?

Currently, I have the following LINQ queries. How can I merge the two queries into one. Basically, write a LINQ query to bring back the results I'd get from
IEnumerable<int> deltaList = people2010.Except(allPeople);
except in a single query.
var people2010 = Contacts.Where(x => x.Contractors
.Any(d => d.ContractorsStatusTrackings
.Any(date => date.StatusDate.Year >= 2010)))
.Select(x => x.ContactID);
var allPeople = Contacts.Where(x => x.Contractors
.Any(m => m.ContactID == x.ContactID))
.Select(x=> x.ContactID);
Thanks!
Why can you not just do Except as you are doing? Don't forget that your people2010 and allPeople variables are just queries - they're not the data. Why not just use them as they are?
If that's not acceptable for some reason, please give us more information - such as whether this is in LINQ to Object, LINQ to SQL etc, and what's wrong with just using Except.
It sounds like you're just looking for a more elegant way to write your query. I believe that this is a more elegant way to write your combined queries:
var deltaList =
from contact in Contacts
let contractors = contact.Contractors
where contractors.Any(ctor => ctor.ContractorStatusTrackings
.Any(date => date.StatusDate.Year >= 2010))
&& !contractors.Any(m => m.ContactID == contact.ContactID)
select contact.ContactID

minimum value in dictionary using linq

I have a dictionary of type
Dictionary<DateTime,double> dictionary
How can I retrive a minimum value and key coresponding to this value from this dictionary using linq ?
var min = dictionary.OrderBy(kvp => kvp.Value).First();
var minKey = min.Key;
var minValue = min.Value;
This is not very efficient though; you might want to consider MoreLinq's MinBy extension method.
If you are performing this query very often, you might want to consider a different data-structure.
Aggregate
var minPair = dictionary.Aggregate((p1, p2) => (p1.Value < p2.Value) ? p1 : p2);
Using the mighty Aggregate method.
I know that MinBy is cleaner in this case, but with Aggregate you have more power and its built-in. ;)
Dictionary<DateTime, double> dictionary;
//...
double min = dictionary.Min(x => x.Value);
var minMatchingKVPs = dictionary.Where(x => x.Value == min);
You could combine it of course if you really felt like doing it on one line, but I think the above is easier to read.
var minMatchingKVPs = dictionary.Where(x => x.Value == dictionary.Min(y => y.Value));
You can't easily do this efficiently in normal LINQ - you can get the minimal value easily, but finding the key requires another scan through. If you can afford that, use Jess's answer.
However, you might want to have a look at MinBy in MoreLINQ which would let you write:
var pair = dictionary.MinBy(x => x.Value);
You'd then have the pair with both the key and the value in, after just a single scan.
EDIT: As Nappy says, MinBy is also in System.Interactive in Reactive Extensions.

Resources