Linq to avoid nested foreach loop to get unique values - c#

I have below query, but it has 2 foreach loops which i consider not good. How can i get distinct value from IEnumerable> object by using linq.
Below is the code i have written,
var floatingIds= subInfo.Ranges.Select(c => c.RangeIDs.Select(s=>s)).Distinct();
var floatIds= new List<Guid>();
foreach (var ids in floatingIds)
foreach (var id in ids)
{
if (!floatIds.Contains(id))
{
floatIds.Add(id);
}
}
I have this post, but still am not getting expected values, but the above code gives correct IDs How do I avoid using nested foreach statements by using lambda or linq in this scenario?

You can use SelectMany to flatten the collection and get all distinct values without any foreach:
var floatIds = subInfo.Ranges
.SelectMany(c => c.RangeIDs.Select(s=>s))
.Distinct()
.ToList();

var floatIds = subInfo.Ranges
.SelectMany(c => c.RangeIDs.Select(s=>s))
.Distinct()
.ToList();

Related

Group by clause inside a nested list

I am trying to apply group by clause to a list element inside a parent list. How can I skip looping and write this within a single linq query
foreach (var record in marketRecordDTOs)
{
record.Sources = record.Sources
.GroupBy(i => i.SourceId)
.Select(i => i.FirstOrDefault())
.ToList();
}
So you can easily create an IEnumerable<> of all your new Sources:
var newSources = marketRecordDTOs.Select(record => record.Sources
.GroupBy(i => i.SourceId)
.Select(i => i.FirstOrDefault())
.ToList()
);
Though, I am not sure what you intend to do with it after that.

Searching for multiple strings using single database query with entity framework and LINQ

Assuming I have a database table (aTable) with two columns
id : int
name: string
Requirements:
I want to retrieve entries where aTable.name is like a list of strings (stringsToSearchFor).
What I am doing:
Currently I am using the following approach
var result=new List<aTable>;
foreach (var aString in stringsToSearchFor)
{
var r = Context.Set<aTable>()
.Any(s => s.name.Contains(searchString))
.ToList();
res.AddRange(r);
}
return result.Distinct();
To optimize it I tried to change the code by eliminating the foreach, to be:
return Context.Set<aTable>()
.Any(s => stringsToSearchFor.Contains(s.name))
.Distinct()
.ToList();
However, this didn't provide the same results as the previous statement. I believe the first statement is correct.
My question: How can I search for multiple strings without creating N database queries (like the 2nd approach)?
Alternative solution: use the EF 6.2 Like:
.Where(x => stringsToSearchFor.Any(s => DbFunctions.Like(x.name, "%" + s + "%")))
Here's the documentation for DbFunctions.Like.
Something like this should work:
string[] stringsToSearchFor = new string[] { "text1", "text2" };
using (MyDbContext model = new MyDbContext())
{
var result = model.aTable
.Where(r => stringsToSearchFor.Any(s => r.name.Contains(s)))
.ToList();
}

Two for loops in lambda expression

How to create the exactly following two for's in lambda expression?
foreach (var item in list1)
{
foreach (var item2 in list2)
{
if (item.number == item2.number)
{
return false;
}
}
}
Since you're just checking to see if any one item matches, you can use Any().
return !list1.Any( item1 => list2.Any(item2 => item2 == item1 ));
I would just use the Intersect function available for lists and this will return you all the elements that are common in 2 lists. If you just want to see if one exists then you can do it very easily by checking the count.
int count = List1.Select(s => s.number).Intersect(List2.Select(s => s.number)).Count;
If you want to know which elements are unique in both lists then use the Exclude method.
var uniqueItems = List1.Select(s => s.number).Except(List2.Select(s => s.number));
Here you go !!
Using Linq Method Syntax :
!list1.Any(item => list2.Any(item2 => item.number == item2.number))
Using Linq Query syntax:
!(from item in list1
from item2 in list2
where item.number==item2.number select item).Any()

How to loop collections in LINQ and pass on data

How do i do this in LINQ - So i dont have to use ForEach or loops?
I can't seem to figure out how to pass a list when some condition is met and this way loop the collection with LINQ.
products.ForEach(delegate(CustomEcomProducts p)
{
p.VariantProducts = variants.Where(prod => prod.VariantParentID == p.ProductID)
.ToList();
});
That's not what LINQ is for. The Q in LINQ stands for "Query".
The best/cleanest/most readable way to do this is the following:
foreach(var product in products)
product.VariantProducts = variants.Where(x => x.VariantParentID == p.ProductID)
.ToList();

Get keys as List<> from Dictionary for certain values

While similar to this question which gave me the LINQ for part of my problem, I'm missing something that seems like it must be obvious to avoid the last step of looping through the dictionary.
I have a Dictionary and I want to get a List of keys for just the items for which the value is true. Right now I'm doing this:
Dictionary<long,bool> ItemChecklist;
...
var selectedValues = ItemChecklist.Where(item => item.Value).ToList();
List<long> values = new List<long>();
foreach (KeyValuePair<long,bool> kvp in selectedValues) {
values.Add(kvp.Key);
}
Is there any way I can go directly to a List<long> without doing that loop?
To do it in a single statement:
var values = ItemChecklist.Where(item => item.Value).Select(item => item.Key).ToList();
Try using Enumerable.Select:
List<long> result = ItemChecklist.Where(kvp => kvp.Value)
.Select(kvp => kvp.Key)
.ToList();

Categories