The first collection should win always.
MSDN:
When the object returned by this method is enumerated, Union enumerates first and second in that order and yields each element that has not already been yielded.
Here is the implementation of Union
(ILSPY, .NET 4), the first collection is enumerated first:
// System.Linq.Enumerable
private static IEnumerable<TSource> UnionIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource current in first)
{
if (set.Add(current))
{
yield return current;
}
}
foreach (TSource current2 in second)
{
if (set.Add(current2))
{
yield return current2;
}
}
yield break;
}
The same applies to Intersect
(and other similar methods in Linq-To-Objects
as well):
When the object returned by this method is enumerated, Intersect enumerates first, collecting all distinct elements of that sequence. It then enumerates second, marking those elements that occur in both sequences. Finally, the marked elements are yielded in the order in which they were collected.
Update: As Rawling has mentioned in his comment MSDN lies at the documentation of Intersect
. I've looked at Intersect
with ILSpy
and it enumerates the second collection first and only then the first, even if is documented the other way around.
Actually Jon Skeet has also mentioned this "lie" in EduLinq: http://msmvps.com/blogs/jon_skeet/archive/2010/12/30/reimplementing-linq-to-objects-part-16-intersect-and-build-fiddling.aspx (in his words: "This is demonstrably incorrect.")
However, even if it isn't implemented as expected it will still return the element of the first collection as you can see in the implementation:
// System.Linq.Enumerable
private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource current in second)
{
set.Add(current);
}
foreach (TSource current2 in first)
{
if (set.Remove(current2))
{
yield return current2;
}
}
yield break;
}