Linq Order By Contains List - c#

I have a List of ints that model.SelectedIngredients and in this example the list contains the values [15128, 4593,15046,]. I use this list then as a filter in my Linq query as follows:
List<INGREDIENT> selectedIngredients = db.INGREDIENT.Where(i => model.SelectedIngredients.Contains(i.IngredientId)).ToList();
However, this sorts the results by IngredientId ascending as default[4593,15046,15128].
What I would like is to get the selectedIngredients back in the same order as they are in model.SelectedIngredients.
I know I could do it in a for loop but I just wondered if there was a way I could do it within the Linq query?
Thanks

You can acomplish this quite easy by using the index of your list with ids.
List<INGREDIENT> selectedIngredients = db.INGREDIENT
.Where(i => model.SelectedIngredients.Contains(i.IngredientId))
.AsEnumerable()
.OrderBy(i => model.SelectedIngredients.IndexOf(i.IngredientId))
.ToList();

List<INGREDIENT> selectedIngredients = db.INGREDIENT
.Where(i => model.SelectedIngredients.Contains(i.IngredientId))
.orderBy(p=>p.Id).ToList();
This is the default one. Determine in the first place by which it is sorted and then order by it.

Related

GroupBy, OrderByDescending using Lambda in Linq

I have a collection and I need to order it by descending date(DateProcessed field) using Linq, first I am grouping by two possible Keys: Booked or Empty. But the data it's not being ordered..
This is my expression:
IEnumerable<IGrouping<string, MyClassMongo>> sub = Model.MyCollection.GroupBy(f => f.IsBooked ? "Booked" : "Empty").OrderByDescending(f => f.FirstOrDefault().DateProcessed);
I'm confused because I am grouping first, I know that after grouping the collection is splitted in two(Booked and Empty) so I am not sure how to handle the sorting because I am grouping first
If you are querying in-memory collection, then just place ordering before grouping:
IEnumerable<IGrouping<string, MyClassMongo>> sub =
Model.MyCollection
.OrderByDescending(f => f.DateProcessed)
.GroupBy(f => f.IsBooked ? "Booked" : "Empty");
Items within each group will be sorted by DateProcessed.
if you want to first Group by and then sort the results within the Group. you can try some thing like below
Model.MyCollection
.GroupBy(f => f.IsBooked,
(f, g) => new{Key=f.DateProcessed, Group = g.OrderByDescending(c=>c.IsBooked)})
.OrderByDescending(f => f.Key);
PS: Code may have syntax issue not tested but the idea should be to create the key withing each group so we can order by

List Filtering in Linq

I have two lists. One is a list of Ids.
I've to filter the second list which is having the Ids in the former list only.
For that, I've written the below code
var Clientidlist = list.GroupBy(p => new {p.CompanyName, p.UserId})
.Select(s => s.Min(m => m.Id));
var olist = list.Where(x => Clientidlist.Contains(x.Id))
.OrderBy(x=>x.CompanyName).ToList();
But I think there something wrong in it. Can anyone help me?

Remove every first element of grouped collection

I have a collection of elements and some of these elements are duplicating. I need to extract all records but only the first record if the record is one of a duplicate set.
I was able to group the elements and find all elements that have duplicates, but how to remove every first element of a group?
var records =
dbContext.Competitors
.GroupBy(x => x.Email)
.Select(x => new { Properties = x,
Count = x.Key.Count() })
.Where(x => x.Count > 1)
.ToList();
EDIT: Seems like it's impossible to accomplish this task with EF, because it fails to translate the desired linq expression to SQL. I'll be happy if someone offer different approach.
To exclude the first record from each email-address group with more than one entry, you could do this:
var records = dbContext.Competitors
.GroupBy(x => x.Email)
.SelectMany(x => (x.Count() == 1) ? x : x.OrderBy(t=>t).Skip(1))
.ToList();
This is the logic :
Group by a property > Select every Group > (Possibly) Sort that > Skip first one
This can be turned into some linq code like this :
//use SelectMany to flat the array
var x = list.GroupBy(g => g.Key).Select(grp => grp.Skip(1)).SelectMany(i => i);

Query an XML using LINQ and excluding where an Attribute value is equal to that of an Element

I have a LINQ query against an XML, that gives me a list of nested lists, each sublist being a list of an elements("row") attributes.
var items = loadbodies.Descendants("row").Select(a => a.Attributes().Select(b => b.Value).ToList()).ToList();
This works as intended but, what I actually need to is query this against another list of values so as not to have sublists added where one of the elements attributes("messageID") is on the second list. I can do this for one value but need to check it against the entire second list.
The query to exclude a single sublist by a single hardcoded value from the second list is below.
var items = loadbodies.Descendants("row").Where(c => (string)c.Attribute("messageID") != "avaluefromthesecondlist").Select(a => a.Attributes().Select(b => b.Value).ToList()).ToList();
Any help would be much appreciated.
Just use Contains. Note that splitting lines helps readability considerably:
var ids = ...; // Some sequence of ids, e.g. a List<string> or HashSet<string>
var items = loadbodies
.Descendants("row")
.Where(row => ids.Contains((string) row.Attribute("messageId")))
.Select(a => a.Attributes()
.Select(b => b.Value)
.ToList())
.ToList();
Note that you could use a Join call too... but so long as you've got relatively few IDs, this should be fine.

Counting grouped data with Linq to Sql

I have a database of documents in an array, each with an owner and a document type, and I'm trying to get a list of the 5 most common document types for a specific user.
var docTypes = _documentRepository.GetAll()
.Where(x => x.Owner.Id == LoggedInUser.Id)
.GroupBy(x => x.DocumentType.Id);
This returns all the documents belonging to a specific owner and grouped as I need them, I now need a way to extract the ids of the most common document types. I'm not too familiar with Linq to Sql, so any help would be great.
This would order the groups by count descending and then take the top 5 of them, you could adapt to another number or completely take out the Take() if its not needed in your case:
var mostCommon = docTypes.OrderByDescending( x => x.Count()).Take(5);
To just select the top document keys:
var mostCommonDocTypes = docTypes.OrderByDescending( x => x.Count())
.Select( x=> x.Key)
.Take(5);
You can also of course combine this with your original query by appending/chaining it, just separated for clarity in this answer.
Using the Select you can get the value from the Key of the Grouping (the Id) and then a count of each item in the grouping.
var docTypes = _documentRepository.GetAll()
.Where(x => x.Owner.Id == LoggedInUser.Id)
.GroupBy(x => x.DocumentType.Id)
.Select(groupingById=>
new
{
Id = groupingById.Key,
Count = groupingById.Count(),
})
.OrderByDescending(x => x.Count);

Categories