Dynamic linq query that Contains ALL from another list - c#

I want to be able to find all orders with items that contain BOTH apples and oranges that I have in a list.
var itemToFind = new List<string>()
{
"apples",
"cookies"
};
How can I rewrite this so that Contains is dynamic?
This returns what I want but how do I make it loop through my list so that it is dynamic?
var query = result
.Where(o => o.OrderItems
.Any(i => i.Item.Name.Contains("apples")))
.Select(x => x)
.Where(y => y.OrderItems
.Any(b => b.Item.Name.Contains("cookies"))).ToList();
// returns 2 orders

Try something like this:
result.Where(o => o.OrderItems.Any(i => itemToFind.All(itf => i.Item.Name.Contains(itf)))).ToList()

This seems to work but not sure if that is the best way.
foreach (var item in listFacets)
{
// append where clause within loop
result = result
.Where(r => r.RecipeFacets
.Any(f => f.Facet.Slug.Contains(item)));
}

Related

Select all distinct last records of column1 and order by column2 in Linq (Not Working Accordingly)

So I have a table like this:
Now I want distinct ShortCode order by the ID descending. In other words, the distinct last records. Like this:
So I tried GroupBy like:
var data = db.ShortCodes.GroupBy(x => x.ShortCode).Select(x => x.FirstOrDefault()).OrderByDescending(s=> s.ID);
This gave me distinct records but not the last ones, nor ordered by ID descending:
Now I also tried like suggested here
var data = db.ShortCodeManager
.GroupBy(s => s. ShortCode)
.Select(g => g.First())
.OrderByDescending(s => s.ID);
This gave me the error The method 'First' can only be used as a final query operation. Consider using the method 'FirstOrDefault' in this instance instead.
So I modified to FirstOrDefault() like:
var data = db.ShortCodeManager
.GroupBy(s => s. ShortCode)
.Select(g => g.FirstOrDefault())
.OrderByDescending(s => s.ID);
This also gave me distinct records but not the last records:
So finally I tried like suggested here:
var data = db.ShortCodeManager.Where(a => a.ID > 0).GroupBy(x => x.ShortCode).OrderByDescending(grp => grp.Max(g => g.ID)).Select(a => a.FirstOrDefault());
Again, this gave me distinct records but not the last ones, nor ordered by ID descending:
So how am I to write the query to get the result I want in Linq? Also note, I need more of the distinct last records than ordering by ID descending. If anyone also knows how to write it in raw SQL it might be useful as well.
This LINQ query should work for your case:
var result = db.ShortCodeManager
.GroupBy(x => x.ShortCode)
.Select(gr => new { Id = gr.Max(g => g.Id), ShortCode = gr.Key})
.ToList();
EDIT:
Based on your comment it looks like you need to cast anonymous object result to ShortCodeManagerModel type and then pass it to your view. So, somethin like this:
var result = db.ShortCodeManager
.GroupBy(x => x.ShortCode)
.Select(gr => new { Id = gr.Max(g => g.Id), ShortCode = gr.Key})
.ToList();
var model = result
.Select(x => new ShortCodeManagerModel { Id = x.Id, ShortCode = x.ShortCode })
.ToList();
And then pass model to you view.

LINQ equal instead of Contains

I need to use equal instead of Contains.
I have an array of codes called selectedDeviceTypeIDs i assume it has two codes {1,2}
I need get result from the query if Devices ids are exactly {1,2} so i have replace selectedDeviceTypeIDs.Contains with selectedDeviceTypeIDs.equal or something like that ...
m => m.Devices.Any(w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID)
if (DeviceTypeIDs != null)
{
Guid[] selectedDeviceTypeIDs = DeviceTypeIDs.Split(',').Select(Guid.Parse).ToArray();
query = query.Where(j => j.HospitalDepartments.Any(jj => jj.Units.Any(m => m.Devices.Any(w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID)))));
}
Use !.Except().Any() to make sure m.Devices doesn't contains any DeviceTypeID not present in selectedDeviceTypeIDs
query = query.Where(j => j.HospitalDepartments.Any(jj => jj.Units
.Where(m => !m.Devices.Select(w => w.DeviceTypeID).Except(selectedDeviceTypeIDs).Any())));
Option 1:
If you care about the Order of the items, use SequenceEqual extension method. This will return false, even if the collection has the items but in different order
m => m.Devices.Any(w => selectedDeviceTypeIDs.SequenceEqual(w.DeviceTypeID)
Option 2:
If you don't care about the order , use All extension method. This will return true, if the items in both collections are same irrespective of the order.
m => m.Devices.Any(w => selectedDeviceTypeIDs.All(w.DeviceTypeID.Contains)
You need to check if the selectedDeviceTypeIDs contains every device, and that every device contains selectedDeviceTypeIDs. You could use this:
query = query
.Where(j =>
j.HospitalDepartments.Any(jj =>
jj.Units.Any(m =>
m.Devices.All(
w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID))
&&
selectedDeviceTypeIDs.All(
g => m.Devices.Select(d => d.DeviceTypeID).Contains(g))
)
)
);

How do I select all distinct strings in a list of lists of another type?

I'm still very new with LINQ. I have the following "simplified" data structure:
List<List<Field>> myData = new List<List<Field>>();
Field consists of two string members, Type and Name.
My goal is to get a List<string> containing all distinct Name corresponding to a given Type. My first approach is this:
var test = myData
.Where(a => a.FindAll(b => b.Type.Equals("testType"))
.Select(c => c.Name)
.Distinct());
Does somebody have a hint for me? =)
You just need to use SelectMany to flatten your list of lists and then proceed as normal
var test = myData.SelectMany(x => x)
.Where(x => x.Type == "testType")
.Select(x => x.Name)
.Distinct()
.ToList();
Or in query syntax
var test = (from subList in myData
from item in subList
where item.Type == "testType"
select item.Name).Distinct().ToList();
Another way to do it using query notation:
var test= from list in myData
from e in list
where e.Type=="testType"
group e.Name by e.Name into g
select g.Key;
But is better go for one of the #juharr's solutions

undefined number of Or-operation on List

I have a List with n-entries. List<MyClass> result
And I have another List with n-Filter options List<string> filters
What i want is to return the result List filtered by the other List.
For an AND-operation its easy like this:
foreach (var filter in filters)
{
results = results.Where(x => x.Result == filter);
}
But how to code for an OR-Operation?
You can use Wherein combination with Any in this case:
results = results.Where(x => filters.Any(f => f == x.Result));
https://msdn.microsoft.com/library/bb534972(v=vs.110).aspx
Others ways:
//Contains, see DAXaholic's post
results = results.Where(x => filters.Contains(x.Result));
https://msdn.microsoft.com/library/bhkz42b3(v=vs.110).aspx
//List Extension method 'Exists'
results = results.Where(x => filters.Exists(f => f == x.Result));
https://msdn.microsoft.com/library/bfed8bca(v=vs.110).aspx
Something like this should work for you
results.Where(x => filters.Contains(x.Result))

C# LINQ getting duplicates from a list

I have a list of objects that have a string, and int and another int.
I want to be able to create a list of all the objects that have a duplicate string.
Here is what I have so far:
MyObject duplicates = allMyObjects.GroupBy(a => a.MyString)
.Where(a => a.Count() > 1)
.ToList();
The error I am getting is that I cannot implicitly convert the type System.Collections.Generic.List<string, MyObject> to MyObject
var duplicates = allMyObjects.GroupBy(a => a.MyString)
.Where(a => a.Count() > 1)
.SelectMany(g=>g)
.ToList();
you need to write
List<MyObject> duplicates = allMyObjects.GroupBy(a => a.MyString)
.Where(a => a.Count() > 1)
.ToList();
You could use ToLookup to make a nice data structure with all the info you need
var objectsByString = allMyObjects.ToLookup(o => o.MyString);
This will return a Lookup<string, MyObject>. You can get the duplicate strings using:
var duplicateStrings = objectsByString.Where(l => l.Count()>1).Select(l => l.Key);
which will return a IEnumerable<string> with the duplicate strings. And, for each duplicate you can access the actual objects that have duplicates using something like this:
string duplicateKey = duplicateStrings.First();
var duplicateObjects = objectsByString[duplicateKey]
which returns a IEnumerable<MyObject> with the items that have that string.
There are several problem, the first is a List-of-MyObject cannot be assigned to MyObject, so let's use var to ignore this for a second.
var duplicates = allMyObjects.GroupBy(a => a.MyString)
.Where(a => a.Count() > 1)
.ToList();
Now, the type of duplicates is List<IGrouping<string, MyObject>> (despite the incorrectly reported error message). Whoops, gotta get rid of (or write to code to account for) the groups!
var duplicates = allMyObjects.GroupBy(a => a.MyString)
.Where(a => a.Count() > 1)
.SelectMany(g => g)
.ToList();
Now the type of duplicates is List<MyObject>, after having selected every ("selected many") object from every group with more than one item. Better, but this still isn't an MyObject. Well, that's fine: fix the declared type of the variable (that var was previously automatically doing)..
List<MyObject> duplicates = /* same as before */;
Or leave var to do it's thing and if an IEnumerable<MyObject> is fine, simply omit the ToList:
var duplicates = allMyObjects.GroupBy(a => a.MyString)
.Where(a => a.Count() > 1)
.SelectMany(g => g);
Go forth and iterate thy duplicates!

Categories

Resources