Foreach with Extension Method on IEnumerable - c#

Quick Question, See this code:
List<int> result = new List<int>();
var list = new List<int> { 1, 2, 3, 4 };
list.Select(value =>
{
result.Add(value);//Does not work??
return value;
});
And :
result.Count == 0 //true
Why result.Add(value) not executed?
However this not executed, Another question that is have a way do a foreach on a IEnumerable with Extention Method?
Except this way: IEnumerable.ToList().Foreach(p=>...)

Why result.Add(value) not executed?
This is because LINQ uses deferred execution. Until you actually enumerate the results (the return of Select), the delegates will not execute.
To demonstrate, try the following:
List<int> result = new List<int>();
var list = new List<int> { 1, 2, 3, 4 };
var results = list.Select(value =>
{
result.Add(value);//Does not work??
return value;
});
foreach(var item in results)
{
// Just iterating through this will cause the above to execute...
}
That being said, this is a bad idea. LINQ queries should not have side effects if you can avoid it. Think of Select as a way to transform your data, not execute code.
However this not executed, Another question that is have a way do a foreach on a IEnumerable with Extention Method?
You could write your own extension method:
public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
foreach(var item in items)
action(item);
}
However, I would recommend not doing this. For details, refer to Eric Lippert's post on the subject.

Select is lazy and the execution is deferred until you start enumerating over the results. You need to consume the resultset by calling .ToArray for example or by looping over the result:
list.Select(value =>
{
result.Add(value);//Does not work??
return value;
}).ToArray();

List<int> result = new List<int>();
var list = new List<int> { 1, 2, 3, 4 };
list.ForEach(delegate(int sValue)
{
result.Add(sValue);
});
This works but all and adds 1 2 3 4 into result. Test it out. I just did.

Related

How do you use LINQ to combine multiple lists in to one list, but with only what is common among all lists? [duplicate]

I have a list of lists which I want to find the intersection for like this:
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 2, 3, 4 };
var list3 = new List<int>() { 3, 4, 5 };
var listOfLists = new List<List<int>>() { list1, list2, list3 };
// expected intersection is List<int>() { 3 };
Is there some way to do this with IEnumerable.Intersect()?
EDIT:
I should have been more clear on this: I really have a list of lists, I don't know how many there will be, the three lists above was just an example, what I have is actually an IEnumerable<IEnumerable<SomeClass>>
SOLUTION
Thanks for all great answers. It turned out there were four options for solving this: List+aggregate (#Marcel Gosselin), List+foreach (#JaredPar, #Gabe Moothart), HashSet+aggregate (#jesperll) and HashSet+foreach (#Tony the Pony). I did some performance testing on these solutions (varying number of lists, number of elements in each list and random number max size.
It turns out that for most situations the HashSet performs better than the List (except with large lists and small random number size, because of the nature of HashSet I guess.)
I couldn't find any real difference between the foreach method and the aggregate method (the foreach method performs slightly better.)
To me, the aggregate method is really appealing (and I'm going with that as the accepted answer) but I wouldn't say it's the most readable solution.. Thanks again all!
How about:
var intersection = listOfLists
.Skip(1)
.Aggregate(
new HashSet<T>(listOfLists.First()),
(h, e) => { h.IntersectWith(e); return h; }
);
That way it's optimized by using the same HashSet throughout and still in a single statement. Just make sure that the listOfLists always contains at least one list.
You can indeed use Intersect twice. However, I believe this will be more efficient:
HashSet<int> hashSet = new HashSet<int>(list1);
hashSet.IntersectWith(list2);
hashSet.IntersectWith(list3);
List<int> intersection = hashSet.ToList();
Not an issue with small sets of course, but if you have a lot of large sets it could be significant.
Basically Enumerable.Intersect needs to create a set on each call - if you know that you're going to be doing more set operations, you might as well keep that set around.
As ever, keep a close eye on performance vs readability - the method chaining of calling Intersect twice is very appealing.
EDIT: For the updated question:
public List<T> IntersectAll<T>(IEnumerable<IEnumerable<T>> lists)
{
HashSet<T> hashSet = null;
foreach (var list in lists)
{
if (hashSet == null)
{
hashSet = new HashSet<T>(list);
}
else
{
hashSet.IntersectWith(list);
}
}
return hashSet == null ? new List<T>() : hashSet.ToList();
}
Or if you know it won't be empty, and that Skip will be relatively cheap:
public List<T> IntersectAll<T>(IEnumerable<IEnumerable<T>> lists)
{
HashSet<T> hashSet = new HashSet<T>(lists.First());
foreach (var list in lists.Skip(1))
{
hashSet.IntersectWith(list);
}
return hashSet.ToList();
}
Try this, it works but I'd really like to get rid of the .ToList() in the aggregate.
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 2, 3, 4 };
var list3 = new List<int>() { 3, 4, 5 };
var listOfLists = new List<List<int>>() { list1, list2, list3 };
var intersection = listOfLists.Aggregate((previousList, nextList) => previousList.Intersect(nextList).ToList());
Update:
Following comment from #pomber, it is possible to get rid of the ToList() inside the Aggregate call and move it outside to execute it only once. I did not test for performance whether previous code is faster than the new one. The change needed is to specify the generic type parameter of the Aggregate method on the last line like below:
var intersection = listOfLists.Aggregate<IEnumerable<int>>(
(previousList, nextList) => previousList.Intersect(nextList)
).ToList();
You could do the following
var result = list1.Intersect(list2).Intersect(list3).ToList();
This is my version of the solution with an extension method that I called IntersectMany.
public static IEnumerable<TResult> IntersectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
using (var enumerator = source.GetEnumerator())
{
if(!enumerator.MoveNext())
return new TResult[0];
var ret = selector(enumerator.Current);
while (enumerator.MoveNext())
{
ret = ret.Intersect(selector(enumerator.Current));
}
return ret;
}
}
So the usage would be something like this:
var intersection = (new[] { list1, list2, list3 }).IntersectMany(l => l).ToList();
This is my one-row solution for List of List (ListOfLists) without intersect function:
var intersect = ListOfLists.SelectMany(x=>x).Distinct().Where(w=> ListOfLists.TrueForAll(t=>t.Contains(w))).ToList()
This should work for .net 4 (or later)
After searching the 'net and not really coming up with something I liked (or that worked), I slept on it and came up with this. Mine uses a class (SearchResult) which has an EmployeeId in it and that's the thing I need to be common across lists. I return all records that have an EmployeeId in every list. It's not fancy, but it's simple and easy to understand, just what I like. For small lists (my case) it should perform just fine—and anyone can understand it!
private List<SearchResult> GetFinalSearchResults(IEnumerable<IEnumerable<SearchResult>> lists)
{
Dictionary<int, SearchResult> oldList = new Dictionary<int, SearchResult>();
Dictionary<int, SearchResult> newList = new Dictionary<int, SearchResult>();
oldList = lists.First().ToDictionary(x => x.EmployeeId, x => x);
foreach (List<SearchResult> list in lists.Skip(1))
{
foreach (SearchResult emp in list)
{
if (oldList.Keys.Contains(emp.EmployeeId))
{
newList.Add(emp.EmployeeId, emp);
}
}
oldList = new Dictionary<int, SearchResult>(newList);
newList.Clear();
}
return oldList.Values.ToList();
}
Here's an example just using a list of ints, not a class (this was my original implementation).
static List<int> FindCommon(List<List<int>> items)
{
Dictionary<int, int> oldList = new Dictionary<int, int>();
Dictionary<int, int> newList = new Dictionary<int, int>();
oldList = items[0].ToDictionary(x => x, x => x);
foreach (List<int> list in items.Skip(1))
{
foreach (int i in list)
{
if (oldList.Keys.Contains(i))
{
newList.Add(i, i);
}
}
oldList = new Dictionary<int, int>(newList);
newList.Clear();
}
return oldList.Values.ToList();
}
This is a simple solution if your lists are all small. If you have larger lists, it's not as performing as hash set:
public static IEnumerable<T> IntersectMany<T>(this IEnumerable<IEnumerable<T>> input)
{
if (!input.Any())
return new List<T>();
return input.Aggregate(Enumerable.Intersect);
}

How to concatenate two IEnumerable<T> into a new IEnumerable<T>?

I have two instances of IEnumerable<T> (with the same T). I want a new instance of IEnumerable<T> which is the concatenation of both.
Is there a built-in method in .NET to do that or do I have to write it myself?
Yes, LINQ to Objects supports this with Enumerable.Concat:
var together = first.Concat(second);
NB: Should first or second be null you would receive a ArgumentNullException. To avoid this & treat nulls as you would an empty set, use the null coalescing operator like so:
var together = (first ?? Enumerable.Empty<string>()).Concat(second ?? Enumerable.Empty<string>()); //amending `<string>` to the appropriate type
The Concat method will return an object which implements IEnumerable<T> by returning an object (call it Cat) whose enumerator will attempt to use the two passed-in enumerable items (call them A and B) in sequence. If the passed-in enumerables represent sequences which will not change during the lifetime of Cat, and which can be read from without side-effects, then Cat may be used directly. Otherwise, it may be a good idea to call ToList() on Cat and use the resulting List<T> (which will represent a snapshot of the contents of A and B).
Some enumerables take a snapshot when enumeration begins, and will return data from that snapshot if the collection is modified during enumeration. If B is such an enumerable, then any change to B which occurs before Cat has reached the end of A will show up in Cat's enumeration, but changes which occur after that will not. Such semantics may likely be confusing; taking a snapshot of Cat can avoid such issues.
You can use below code for your solution:-
public void Linq94()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var allNumbers = numbersA.Concat(numbersB);
Console.WriteLine("All numbers from both arrays:");
foreach (var n in allNumbers)
{
Console.WriteLine(n);
}
}
I know this is a relatively old post, but if you wanted to concatenate multiple IEnumerable's, I use the following
var joinedSel = new[] { first, second, third }.Where(x => x != null).SelectMany(x => x);
This eliminates any null IEnumerable's and allows for multiple concatenations.
Based off of craig1231's answer, I've created some extension methods...
public static IEnumerable<T> JoinLists<T>(this IEnumerable<T> list1, IEnumerable<T> list2)
{
var joined = new[] { list1, list2 }.Where(x => x != null).SelectMany(x => x);
return joined ?? Enumerable.Empty<T>();
}
public static IEnumerable<T> JoinLists<T>(this IEnumerable<T> list1, IEnumerable<T> list2, IEnumerable<T> list3)
{
var joined = new[] { list1, list2, list3 }.Where(x => x != null).SelectMany(x => x);
return joined ?? Enumerable.Empty<T>();
}
public static IEnumerable<T> JoinMany<T>(params IEnumerable<T>[] array)
{
var final = array.Where(x => x != null).SelectMany(x => x);
return final ?? Enumerable.Empty<T>();
}
// The answer that I was looking for when searching
public void Answer()
{
IEnumerable<YourClass> first = this.GetFirstIEnumerableList();
// Assign to empty list so we can use later
IEnumerable<YourClass> second = new List<YourClass>();
if (IwantToUseSecondList)
{
second = this.GetSecondIEnumerableList();
}
IEnumerable<SchemapassgruppData> concatedList = first.Concat(second);
}

Find the number of differences between two lists

I want to compare two lists with the same number of elements, and find the number of differences between them. Right now, I have this code (which works):
public static int CountDifferences<T> (this IList<T> list1, IList<T> list2)
{
if (list1.Count != list2.Count)
throw new ArgumentException ("Lists must have the same number of elements", "list2");
int count = 0;
for (int i = 0; i < list1.Count; i++) {
if (!EqualityComparer<T>.Default.Equals (list1[i], list2[i]))
count++;
}
return count;
}
This feels messy to me, and it seems like there must be a more elegant way to achieve it. Is there a way, perhaps, to combine the two lists into a single list of tuples, then simple examine each element of the new list to see if both elements are equal?
Since order in the list does count this would be my approach:
public static int CountDifferences<T>(this IList<T> list1, IList<T> list2)
{
if (list1.Count != list2.Count)
throw new ArgumentException("Lists must have the same number of elements", "list2");
int count = list1.Zip(list2, (a, b) => a.Equals(b) ? 0 : 1).Sum();
return count;
}
Simply merging the lists using Enumerable.Zip() then summing up the differences, still O(n) but this just enumerates the lists once.
Also this approach would work on any two IEnumerable of the same type since we do not use the list indexer (besides obviously in your count comparison in the guard check).
I think your approach is fine, but you could use LINQ to simplify your function:
public static int CountDifferences<T>(this IList<T> list1, IList<T> list2)
{
if(list1.Count != list2.Count)
throw new ArgumentException("Lists must have same # elements", "list2");
return list1.Where((t, i) => !Equals(t, list2[i])).Count();
}
The way you have it written in the question, I don't think Intersect does what you're looking for. For example, say you have:
var list1 = new List<int> { 1, 2, 3, 4, 6, 8 };
var list2 = new List<int> { 1, 2, 4, 5, 6, 8 };
If you run list1.CountDifferences(list2), I'm assuming that you want to get back 2 since elements 2 and 3 are different. Intersect in this case will return 5 since the lists have 5 elements in common. So, if you're looking for 5 then Intersect is the way to go. If you're looking to return 2 then you could use the LINQ statement above.
Try something like this:
var result = list1.Intersect(list2);
var differences = list1.Count - result.Count();
If order counts:
var result = a.Where((x,i) => x !=b[i]);
var differences = result.Count();
You want the Intersect extension method of Enumerable.
public static int CountDifferences<T> (this IList<T> list1, IList<T> list2)
{
if (list1.Count != list2.Count)
throw new ArgumentException ("Lists must have the same number of elements", "list2");
return list1.Count - list1.Intersect(list2).Count();
}
You can use the extension method Zip of List.
List<int> lst1 = new List<int> { 1, 2, 3, 4, 5 };
List<int> lst2 = new List<int> { 6, 2, 9, 4, 5 };
int cntDiff = lst1.Zip(lst2, (a, b) => a != b).Count(a => a);
// Output is 2

Intersection of multiple lists with IEnumerable.Intersect()

I have a list of lists which I want to find the intersection for like this:
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 2, 3, 4 };
var list3 = new List<int>() { 3, 4, 5 };
var listOfLists = new List<List<int>>() { list1, list2, list3 };
// expected intersection is List<int>() { 3 };
Is there some way to do this with IEnumerable.Intersect()?
EDIT:
I should have been more clear on this: I really have a list of lists, I don't know how many there will be, the three lists above was just an example, what I have is actually an IEnumerable<IEnumerable<SomeClass>>
SOLUTION
Thanks for all great answers. It turned out there were four options for solving this: List+aggregate (#Marcel Gosselin), List+foreach (#JaredPar, #Gabe Moothart), HashSet+aggregate (#jesperll) and HashSet+foreach (#Tony the Pony). I did some performance testing on these solutions (varying number of lists, number of elements in each list and random number max size.
It turns out that for most situations the HashSet performs better than the List (except with large lists and small random number size, because of the nature of HashSet I guess.)
I couldn't find any real difference between the foreach method and the aggregate method (the foreach method performs slightly better.)
To me, the aggregate method is really appealing (and I'm going with that as the accepted answer) but I wouldn't say it's the most readable solution.. Thanks again all!
How about:
var intersection = listOfLists
.Skip(1)
.Aggregate(
new HashSet<T>(listOfLists.First()),
(h, e) => { h.IntersectWith(e); return h; }
);
That way it's optimized by using the same HashSet throughout and still in a single statement. Just make sure that the listOfLists always contains at least one list.
You can indeed use Intersect twice. However, I believe this will be more efficient:
HashSet<int> hashSet = new HashSet<int>(list1);
hashSet.IntersectWith(list2);
hashSet.IntersectWith(list3);
List<int> intersection = hashSet.ToList();
Not an issue with small sets of course, but if you have a lot of large sets it could be significant.
Basically Enumerable.Intersect needs to create a set on each call - if you know that you're going to be doing more set operations, you might as well keep that set around.
As ever, keep a close eye on performance vs readability - the method chaining of calling Intersect twice is very appealing.
EDIT: For the updated question:
public List<T> IntersectAll<T>(IEnumerable<IEnumerable<T>> lists)
{
HashSet<T> hashSet = null;
foreach (var list in lists)
{
if (hashSet == null)
{
hashSet = new HashSet<T>(list);
}
else
{
hashSet.IntersectWith(list);
}
}
return hashSet == null ? new List<T>() : hashSet.ToList();
}
Or if you know it won't be empty, and that Skip will be relatively cheap:
public List<T> IntersectAll<T>(IEnumerable<IEnumerable<T>> lists)
{
HashSet<T> hashSet = new HashSet<T>(lists.First());
foreach (var list in lists.Skip(1))
{
hashSet.IntersectWith(list);
}
return hashSet.ToList();
}
Try this, it works but I'd really like to get rid of the .ToList() in the aggregate.
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 2, 3, 4 };
var list3 = new List<int>() { 3, 4, 5 };
var listOfLists = new List<List<int>>() { list1, list2, list3 };
var intersection = listOfLists.Aggregate((previousList, nextList) => previousList.Intersect(nextList).ToList());
Update:
Following comment from #pomber, it is possible to get rid of the ToList() inside the Aggregate call and move it outside to execute it only once. I did not test for performance whether previous code is faster than the new one. The change needed is to specify the generic type parameter of the Aggregate method on the last line like below:
var intersection = listOfLists.Aggregate<IEnumerable<int>>(
(previousList, nextList) => previousList.Intersect(nextList)
).ToList();
You could do the following
var result = list1.Intersect(list2).Intersect(list3).ToList();
This is my version of the solution with an extension method that I called IntersectMany.
public static IEnumerable<TResult> IntersectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
using (var enumerator = source.GetEnumerator())
{
if(!enumerator.MoveNext())
return new TResult[0];
var ret = selector(enumerator.Current);
while (enumerator.MoveNext())
{
ret = ret.Intersect(selector(enumerator.Current));
}
return ret;
}
}
So the usage would be something like this:
var intersection = (new[] { list1, list2, list3 }).IntersectMany(l => l).ToList();
This is my one-row solution for List of List (ListOfLists) without intersect function:
var intersect = ListOfLists.SelectMany(x=>x).Distinct().Where(w=> ListOfLists.TrueForAll(t=>t.Contains(w))).ToList()
This should work for .net 4 (or later)
After searching the 'net and not really coming up with something I liked (or that worked), I slept on it and came up with this. Mine uses a class (SearchResult) which has an EmployeeId in it and that's the thing I need to be common across lists. I return all records that have an EmployeeId in every list. It's not fancy, but it's simple and easy to understand, just what I like. For small lists (my case) it should perform just fine—and anyone can understand it!
private List<SearchResult> GetFinalSearchResults(IEnumerable<IEnumerable<SearchResult>> lists)
{
Dictionary<int, SearchResult> oldList = new Dictionary<int, SearchResult>();
Dictionary<int, SearchResult> newList = new Dictionary<int, SearchResult>();
oldList = lists.First().ToDictionary(x => x.EmployeeId, x => x);
foreach (List<SearchResult> list in lists.Skip(1))
{
foreach (SearchResult emp in list)
{
if (oldList.Keys.Contains(emp.EmployeeId))
{
newList.Add(emp.EmployeeId, emp);
}
}
oldList = new Dictionary<int, SearchResult>(newList);
newList.Clear();
}
return oldList.Values.ToList();
}
Here's an example just using a list of ints, not a class (this was my original implementation).
static List<int> FindCommon(List<List<int>> items)
{
Dictionary<int, int> oldList = new Dictionary<int, int>();
Dictionary<int, int> newList = new Dictionary<int, int>();
oldList = items[0].ToDictionary(x => x, x => x);
foreach (List<int> list in items.Skip(1))
{
foreach (int i in list)
{
if (oldList.Keys.Contains(i))
{
newList.Add(i, i);
}
}
oldList = new Dictionary<int, int>(newList);
newList.Clear();
}
return oldList.Values.ToList();
}
This is a simple solution if your lists are all small. If you have larger lists, it's not as performing as hash set:
public static IEnumerable<T> IntersectMany<T>(this IEnumerable<IEnumerable<T>> input)
{
if (!input.Any())
return new List<T>();
return input.Aggregate(Enumerable.Intersect);
}

C# - Finding the common members of two List<T>s - Lambda Syntax

So I wrote this simple console app to aid in my question asking. What is the proper way to use a lambda expression on line 3 of the method to get the common members. Tried a Join() but couldn't figure out the correct syntax. As follow up... is there a non-LINQ way to do this in one line that I missed?
class Program
{
static void Main(string[] args)
{
List<int> c = new List<int>() { 1, 2, 3 };
List<int> a = new List<int>() { 5, 3, 2, 4 };
IEnumerable<int> j = c.Union<int>(a);
// just show me the Count
Console.Write(j.ToList<int>().Count.ToString());
}
}
You want Intersect():
IEnumerable<int> j = c.Intersect(a);
Here's an OrderedIntersect() example based on the ideas mentioned in the comments. If you know your sequences are ordered it should run faster — O(n) rather than whatever .Intersect() normally is (don't remember off the top of my head). But if you don't know they are ordered, it likely won't return correct results at all:
public static IEnumerable<T> OrderedIntersect<T>(this IEnumerable<T> source, IEnumerable<T> other) where T : IComparable
{
using (var xe = source.GetEnumerator())
using (var ye = other.GetEnumerator())
{
while (xe.MoveNext())
{
while (ye.MoveNext() && ye.Current.CompareTo(xe.Current) < 0 )
{
// do nothing - all we care here is that we advanced the y enumerator
}
if (ye.Current.Equals(xe.Current))
yield return xe.Current;
else
{ // y is now > x, so get x caught up again
while (xe.MoveNext() && xe.Current.CompareTo(ye.Current) < 0 )
{ } // again: just advance, do do anything
if (xe.Current.Equals(ye.Current)) yield return xe.Current;
}
}
}
}
If you by lambda syntax mean a real LINQ query, it looks like this:
IEnumerable<int> j =
from cItem in c
join aitem in a on cItem equals aItem
select aItem;
A lambda expression is when you use the => operator, like in:
IEnumerable<int> x = a.Select(y => y > 5);
What you have with the Union method really is a non-LINQ way of doing it, but I suppose that you mean a way of doing it without extension methods. There is hardly a one-liner for that. I did something similar using a Dictionary yesterday. You could do like this:
Dictaionary<int, bool> match = new Dictaionary<int, bool>();
foreach (int i in c) match.Add(i, false);
foreach (int i in a) {
if (match.ContainsKey(i)) {
match[i] = true;
}
}
List<int> result = new List<int>();
foreach (KeyValuePair<int,bool> pair in match) {
if (pair.Value) result.Add(pair.Key);
}

Categories