LINQ query OrderBy doesn't work - c#

_db.InstellingAdressens
.Where(l => l.GEMEENTE.Contains(gem_query))
.OrderBy(q => q.GEMEENTE)
.Select(q => q.GEMEENTE)
.Distinct();
this is the query. it returns a List<string> but the strings are not ordered at all. Why does the OrderBy have no effect? and how to fix it?

Try putting OrderBy at the end of your call.
_db.InstellingAdressens.
Where(l => l.GEMEENTE.Contains(gem_query)).
Select(q=>q.GEMEENTE).Distinct().
OrderBy(q=>q).ToList();

Distinct has no knowledge that you have ordered your items before it gets them, so it can't use that knowledge. As such, it has to assume the items are unordered, and will thus just do what it wants with them.
A typical implementation will use a hashtable, which isn't ordered by what you normally want the items to be ordered by, so the result from the distinct operation is an unordered set.
So as others have suggested, change the ordering of your calls to do the ordering last, and you should get what you want.

Change the order of calls
_db.InstellingAdressens.Where(l => l.GEMEENTE.Contains(gem_query)).Select(q=>q.GEMEENTE).Distinct().OrderBy(q=>q.GEMEENTE).ToList();

Try this just put orderby last of the query
_db.InstellingAdressens
.Where(l => l.GEMEENTE.Contains(gem_query))
.Select(q=>q.GEMEENTE)
.Distinct()
.OrderBy(q=>q.GEMEENTE).ToList();

Related

ordering of OrderBy, Where, Select in the Linq query

Considering this sample code
System.Collections.ArrayList fruits = new System.Collections.ArrayList();
fruits.Add("mango");
fruits.Add("apple");
fruits.Add("lemon");
IEnumerable<string> query = fruits.Cast<string>()
.OrderBy(fruit => fruit)
.Where(fruit => fruit.StartsWith("m"))
.Select(fruit => fruit);
I have two questions:
Do I need to write the last Select clause if Where returns the same type by itself? The example is from msdn, why do they always write it?
What is the correct order of these methods? Does the order affect something? What if I swap Select and Where, or OrderBy?
No, the Select is not necesssary if you are not actually transforming the returned type.
In this case, the ordering of the method calls could have an impact on performance. Sorting all the objects before filtering is sure to take longer than filtering and then sorting a smaller data set.
The .Select is unnecessary in this case because .Cast already guarantees that you're working with IEnumerable<string>.
The ordering of .OrderBy and .Where doesn't affect the results of the query, but in general if you use .Where first you'll get better performance because there will be fewer elements to sort.

Selecting items in an ordered list after a certain entry

I have an ordered list of objects. I can easily find an item in the list by using the following code:
purchaseOrders.FirstOrDefault(x => x.OurRef.Equals(lastPurchaseOrder, StringComparison.OrdinalIgnoreCase))
What I want to do is select all the items in the list that appear after this entry. How best to achieve this? Would it to be to get the index of this item and select a range?
It sounds like you want SkipWhile:
var orders = purchaseOrders.SkipWhile(x => !x.OurRef.Equals(...));
Once the iterator has stopped skipping, it doesn't evaluate the predicate for later entries.
Note that that code will include the entry that doesn't match the predicate, i.e. the one with the given reference. It will basically give you all entries from that order onwards. You can always use .Skip(1) if you want to skip that:
// Skip the exact match
var orders = purchaseOrders.SkipWhile(x => !x.OurRef.Equals(...)).Skip(1);
This will be linear, mind you... if the list is ordered by x.OurRef you could find the index with a binary search and take the range from there onwards... but I wouldn't do that unless you find that the simpler code causes you problems.
Probably you should take a look at LINQ's combination of Reverse and TakeWhile methods, if I understand your question correctly.
It may look like purchaseOrder.Reverse().TakeWhile(x => !x.OurRef.Equals(lastPurchaseOrder, StringComparison.OrdinalIgnoreCase)).
Sorry if code is unformatted, I'm from mobile web right now.
May be you want something like this:
int itemIndex = list.IndexOf(list.FirstOrDefault(x => x.OurRef.Equals(lastPurchaseOrder, StringComparison.OrdinalIgnoreCase));
var newList = list.Where((f, i) => i >= itemIndex);

Linq using sum() in list within a list

The relationship between them is one order to many journals. Now I want to get the sum of all pending orders (or records that are flagged as false under IsDelivered in Order entity).
So far, I have this query but can't seem to get working when I add .Sum()
Orders
.Where(o => o.IsDelivered == false)
.Select(o => new {
pendingOrders = o.Journals.Sum(j => j.TotalAmount)
})
So far this results to:
In a nutshell, how can I get the sum of them? If query needs to be altered or should be a new one. It is welcome. Any help would be much appreciated. Thanks!
You can do it in several ways:
You could add Sum(n => n.pendingOrders) to the end of your query to add up the values, or
You could use SelectMany before Select, and use Sum instead of Select.
Either of the two approaches is going to work.
In this case, it is easiest to use SelectMany (MSDN) to flatten your collections, then use Sum:
Orders.Where(o => !o.IsDelivered).SelectMany(o => o.Journals).Sum(j => j.TotalAmount);

why Linq GroupBy After OrderBy dismissed order operation?

I have a Action model with Session Navigation Property,
Consider this code:
var x=db.Actions.OrderBy(p => p.Session.Number).ThenBy(p => p.Date);//it's OK
x is a ordered Action, but when grouped on x, group not iterate on x(base on Action.Session) manually on ordered enumerable:
var y=x.GroupBy(p=>p.Session).ToArray()
y have a group(Key,IGrouping) of sessions but why group.Key not ordered base on Session.Number?
How to i reached a group of Session order by number and each group ordered by date?
Because it's Enumerable.GroupBy that preserves order. No such promise is made for Queryable.GroupBy.
From the documentation of the former:
The IGrouping(Of TKey, TElement) objects are yielded in an order based on
order of the elements in source that produced the first key of each
IGrouping(Of TKey, TElement). Elements in a grouping are yielded in the order
they appear in source.
You're calling the latter, and the above is not mentioned. Call OrderBy after GroupBy to make it work.
Update: since you apparently want to sort on more than just the GroupBy key, you should be able to use another GroupBy overload to specify that each session's list of actions is to be sorted:
db.Actions.GroupBy(
p => p.Session,
(session, actions) => new {
Session = session,
Actions = actions.OrderBy(p => p.Date)
}).OrderBy(p => p.Session.Number).ToArray();
Because it is not defined that GroupBy preserves either insertion order or the underlying key order (in the same way that Dictionay<,> makes no such guarantee, for local in-memory work). Just order after grouping, instead:
var y = db.Actions.GroupBy(p=>p.Session).OrderBy(grp => grp.Key).ToArray();
In particular, note that to translate the order directly would require it to analyse the expression to spot which parts of the ordering overlap with the grouping (and which don't), which is non-trivial.
Thanks to #Marc Gravell & #hvd for note about groupby IGrouping(Of TKey, TElement) not preserves order of TKey but preserves order of TElement.
So my answer for my final question (How to i reached a group of Session order by number and each group ordered by date?) is:
var x= db.Actions
.OrderBy(p => p.ActionDateTime)
.GroupBy(p => p.Session)
.OrderBy(q => q.Key.Number)
.ToArray();
Just the name GroupBy suggests that the data queried at that moment will be grouped, aggregated (call how you want) into another data unit based on parameter provided.
In general if you want to see result sorted the Sort() function call should be the last one in sequence.

LINQ: Getting the row with the maximum value of a given attribute

I have a bunch of rows grouped on an attribute called MyID. Now I want the one row from each group where the StatusDate attribute is the highest in that one group.
This is what I've come up with.
rows.Select(x => x.Where(y => y.StatusDate == x.Max(z => z.StatusDate)).First())
With a bit more explanation:
rows.Select(x => // x is a group
x.Where(y => // get all rows in that group where...
// the status date is equal to the largest
// status date in the group
y.StatusDate == x.Max(z => z.StatusDate)
).First()) // and then get the first one of those rows
Is there any faster or more idiomatic way to do this?
One alternative would be to use:
rows.Select(x => x.OrderByDescending(y => y.StatusDate).First());
... and check that the query optimiser knows that it doesn't really need to sort everything. (This would be disastrous in LINQ to Objects, but you could use MaxBy from MoreLINQ in that case :)
(Apologies for previous version - I hadn't fully comprehended the grouping bit.)
Don't know if this is Linq to SQL, but if it is, you could alternatively accomplish via a rank() function in SQL (rank each group by date, then select the first ranked row from each), then call this as a stored proc from LINQ. I think that's an approch that is becoming more idiomatic as people hit the bounderies of LINQ2SQL...

Categories