How to use Orderby Clause with IEnumerable - c#

I have written following code:
IEnumerable<Models.bookings> search = new List<bookings>();
search = new available_slotsRepositories().GetAvailableSlot(param1,param2);
var data = from s in search.AsEnumerable().
OrderByDescending(c => c.BookingDate)
select s;
i have also tried this and it does not work:
search.OrderByDescending(c => c.BookingDate);
Third line gives me following error:
Expression cannot contain lambda expressions
Any one guide me how can i fix this issue?
Any help would be appreciated.
Thank you!

why r u using new List()??
follow the below pattern
IEnumerable<Step> steps = allsteps.Where(step => step.X <= Y);
steps = steps.OrderBy(step => step.X);
NOTE:
IEnumerable makes no guarantees about ordering, but the implementations that use IEnumerable may or may not guarantee ordering.
For instance, if you enumerate List, order is guaranteed, but if you enumerate HashSet no such guarantee is provided, yet both will be enumerated using the IEnumerable interface
Perhaps you are looking for the IOrderedEnumerable interface? It is returned by extensions methods like OrderBy() and allow for subsequent sorting with ThenBy().

Have you tried
var data = (from s in search
OrderByDescending(c => c.BookingDate)
select s).ToList();
That will make a List which is IEnumerable.

I'm not sure why you need "new" if as you say GetAvailableSlot returns an IEnumerable. What I think your code should look like assuming GetAvailableSlot returns IEnumerable is this:
var data = available_slotsRepositories().GetAvailableSlot(param1,param2).ToList().OrderByDescending(c => c.BookingDate);
All you're doing to your recordset is ordering the results there is no need to have multiple variables declared. If this still doesn't work then we need to see more of the code in order to see what the problem is...

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.

linq: separate orderby and thenby statements

I'm coding through the 101 Linq tutorials from here:
http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
Most of the examples are simple, but this one threw me for a loop:
[Category("Ordering Operators")]
[Description("The first query in this sample uses method syntax to call OrderBy and ThenBy with a custom comparer to " +
"sort first by word length and then by a case-insensitive sort of the words in an array. " +
"The second two queries show another way to perform the same task.")]
public void Linq36()
{
string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry", "b1" };
var sortedWords =
words.OrderBy(a => a.Length)
.ThenBy(a => a, new CaseInsensitiveComparer());
// Another way. TODO is this use of ThenBy correct? It seems to work on this sample array.
var sortedWords2 =
from word in words
orderby word.Length
select word;
var sortedWords3 = sortedWords2.ThenBy(a => a, new CaseInsensitiveComparer());
No matter which combination of words I throw at it the length is always the first ordering criteria ... even though I don't know how the second statement (with no orderby!) knows what the original orderby clause was.
Am I going crazy? Can anyone explain how Linq "remembers" what the original ordering was?
The return type of OrderBy is not IEnumerable<T>. It's IOrderedEnumerable<T>. This is an object that "remembers" all of the orderings it's been given, and as long as you don't call another method that turns the variable back into an IEnumerable it will retain that knowledge.
See Jon Skeets wonderful blog series Eduling in which he re-implements Linq-to-objects for more info. The key entries on OrderBy/ThenBy are:
IOrderedEnumerable
OrderBy, OrderByDescending, ThenBy, ThenByDescending
This is because LINQ is lazy, the first i.e. all the evaluation only happens when you enumerate the sequence.. the expression tree that has been constructed gets executed.
Your question really doesn't make much sense on the surface because you're not considering the nature of the deferred execution. It doesn't "remember" in either case truthfully, it simply isn't executed until it's really needed. If you run over your examples in the debugger you will find that these generate identical (structurally anyway) statements. Consider:
var sortedWords =
words.OrderBy(a => a.Length)
.ThenBy(a => a, new CaseInsensitiveComparer());
You've explicitly told it to OrderBy, ThenBy. Each statement is stacked on until they're all complete, and the finally query is constructed to look like (psuedo):
Select from sorted words, order by length, order by comparer
Then once that is all ready to go it is executed and placed into sortedWords. Now consider:
var sortedWords2 =
from word in words
orderby word.Length // You're telling it to sort here
select word;
// Now you're telling it to ThenBy here
var sortedWords3 = sortedWords2.ThenBy(a => a, new CaseInsensitiveComparer());
And then once those queries are stacked up it will be executed. However, it WON'T be executed until you NEED them. sortedWords3 won't really have any value until you act on it because the need for it is deferred. So in both cases, you're basically saying to the compiler:
Wait until I'm done building my query
Select from source
Order by length
Then by comparer
Ok do your stuff.
Note: To sum up, LINQ doesn't "remember", it simply doesn't execute until you're done giving it instructions to execute. Then it stacks them up into a query and runs them all at once when they're needed.

best way to use LINQ to query against a list

i have a collection
IEnumerable<Project>
and i want to do a filter based on project's Id property to included any id that is in a list:
List<int> Ids
what is the best way to do a where clause to check if a property is contained in a list.
var filteredProjectCollection = projectCollection.Where(p => Ids.Contains(p.id));
You may be able to get a more efficient implementation using the Except method:
var specialProjects = Ids.Select(id => new Project(id));
var filtered = projects.Except(specialProjects, comparer);
The tricky thing is that Except works with two collections of the same type - so you want to have two collections of projects. You can get that by creating new "dummy" projects and using comparer that compares projects just based on the ID.
Alternatively, you could use Except just on collections of IDs, but then you may need to lookup projects by the ID, which makes this approach less appealing.
var nonExcludedProjects = from p in allprojects where Ids.Contains(p => p.Id) select p;
If you're going to use one of the .Where(p=> list.Contains(p)) answers, you should consier first making a HashSet out of the list so that it doesn't have to do an O(n) search each time. This cuts running time from O(mn) to O(m+n).
I'm not sure that I understand your question but I'll have a shot.
If you have: IEnumerable enumerable,
and you want to filter it such that it only contians items that are also present in the list: List list,
then: IEnumerable final = enumerable.Where(e => list.Contains(e));

How to use LINQ to SQL to create ranked search results?

I am looking for a way to use l2s to return ranked result based on keywords.
I would like to take a keyword and be able to search the table for that keyword using .contains(). The trick that I haven't been able to figure out is how to get a count of how many times that keyqord appears, and then .OrderByDescending() based on that count.
So if i had some thing like:
string keyword = "SomeKeyword";
IQueryable<Article> searchResults = from a in GenesisRepository.Article
where a.Body.Contains(keyword)
select a;
What is the best way to order searchResults based on the number of times keyword appears in a.Body?
Thanks for any help.
try inserting order by a.Body.Split(' ').Count(w=>w == keyword). That should allow you to see that the concept works. However, I STRONGLY recommend that the final version include this as part of the select projection, possibly using a key-value pair, and order by the property name:
string keyword = "SomeKeyword";
//EDIT: restructured query to force the ordering to be done on the projection,
//not the source.
IQueryable<Article> searchResults = (from a in GenesisRepository.Article
where a.Body.Contains(keyword)
select new KeyValuePair<int, Article>(
a.Body.Split(' ').Count(w=>w == keyword), a))
.OrderBy(kvp=>kvp.Key);
The reason is performance; the Split().Count() method chain is linear-complexity, and will be evaluated for every comparison of two values, making the overall sort N^2logN complexity (slow).
EDIT: Also, understand that a.Body.Contains(keyword) will not search by whole words, and so will return articles that contain "SomeKeywordLongerThanSearch" and "ThisIsSomeKeyword" as well as "SomeKeyword". You can avoid this with a Regex match on the pattern "\bSomeKeyword\b", which will only match instances of SomeKeyword with a word boundary immediately before and after.
This is a little hack I came up with, pretty simple but definitely not a "best practices" one.
IQueryable<Article> searchResults = from a in GenesisRepository.Article
where a.Body.Contains(keyword)
orderby a.Body.Split(new string[] { keyword }, StringSplitOptions.RemoveEmptyEntries).Count() descending
select a;
Maybe this will work...
IQueryable<Article> searchResults = from a in GenesisRepository.Article
where a.Body.Contains(keyword)
select a;
searchResults.OrderByDescending(s => Regex.Matches(a.Body, keyword).Count);

LINQ: Help with linq query and contains for an IEnumerable<string>?

Can anyone help?
I have a linq query which is embedded inside a extension method, it was working as v.RentalStatus was a String. I am now using a Group on my original query (the query is quite complex so i won't put it here).
The importante thing is that v.RentalStatus = IEnumerable hence it can contain things like
A (meaning active)
R (meaning rented)
U (unavailable)
etc - many more
I create a list of what i would like to get back and store this in statusStringList, so for example lets say the list contains A and R
This is my code from before when the v.RentalStatus was just a string, can anyone tell me how i can modify this to work.
var statusStringList = rentalStatus.ToList().ConvertAll<string>(st => st.GetStringValue());
return from v in qry
where statusStringList.Contains(v.RentalStatus)
select v;
If it helps this is part of my query which returns the RentalStatus - its part of a group query but the RentalStatus is not in the group by
RentalStatus= g1.Select( j => j.IdRentalStatus).Distinct(),
g1 is my group by, so if you imagine there are 10 "A", 5 "U" .. then it would return an ienumerable of A and U ... as i am using Distinct. Not 10 As and 5 Us
I hope i have explained it well, please tell me if i haven't
I would appreciate any help from anyone ..
thanks
EDIT
This is my extension signature but not that it matters.
public static IQueryable<Rentals> WithStatus(this IQueryable<Rentals> qry, IList<Contants.Statuses> rentalStatus)
{
EDIT
As mentioned previously when v.RentalStatus was a string it was working but now its IEnumerable - hence a collection.. and it errors with this
Argument '1': cannot convert from 'System.Collections.Generic.IEnumerable<string>' to 'string'
If RentalStatus has changed from a string to a IEnumerable<string> then your comparing 2 list... I think this should work:
return from v in qry
where v.RentalStatus.Any(status => statusStringList.Contains(status))
select v;
This should give you any rentals that have a status that is in the list you are providing
Edit:
Yeah I would spend some time learn lambda expressions. Seems like they are being used more and more and with good reason. Here are a few links for tutorials:
An Extensive Examination of LINQ: Lambda Expressions and Anonymous Types
.NET Lambda Expressions – Resources
"WHERE" RentalStatus = Containing any
of itself - arrgghh -
Is that true? I thought the list of rentalStatuses is a parameter in your method. I was thinking your query basically would allow me to get all the rentals that have a status that matches any of the list that I specified. One list lives on your Rental object and the other is the one I pass in...
As to why the order in mine worked. I have some questions:
Are you using this to query a database? Are you able to look at the tsql it generates?
If so, I would look at the tsql and see what the difference is. I would have to check myself. I got lucky I guess.
You could try something like this:
where statusStringList.Any(x => v.RentalStatus.Contains(x))
I am not sure but I think that for a Contains to work in Linq to SQL it must be an array of strings (or ints or ...) and not any IEnumerable. I would thus try:
var statusStringArray = rentalStatus.ToList().ConvertAll<string>(st => st.GetStringValue()).ToArray();
return from v in qry
where statusStringArray.Contains(v.RentalStatus)
select v;
There might be other issues though, I did not look that much.
Try this:
return from v in qry
where rentalStatus.Any( r => r.IdRentalStatus == v.RentalStatus)
select v;

Categories