Salo
Salo

Reputation: 181

Linq find differences in two lists

I have two list of members like this:

Before: Peter, Ken, Julia, Tom

After: Peter, Robert, Julia, Tom

As you can see, Ken is is out and Robert is in.

What I want is to detect the changes. I want a list of what has changed in both lists. How can linq help me?

Upvotes: 18

Views: 9382

Answers (4)

SergeyS
SergeyS

Reputation: 4510

Here is the version having O(n) complexity, provided your sequences are both ordered:

    public static IEnumerable<T> SymmetricDifference<T>(IEnumerable<T> coll1, IEnumerable<T> coll2, IComparer<T> cmp)
    {
        using (IEnumerator<T> enum1 = coll1.GetEnumerator())
        using (IEnumerator<T> enum2 = coll2.GetEnumerator())
        {
            bool enum1valid = enum1.MoveNext();
            bool enum2valid = enum2.MoveNext();
            while (enum1valid && enum2valid)
            {
                int cmpResult = cmp.Compare(enum1.Current, enum2.Current);
                if (cmpResult < 0)
                {
                    yield return enum1.Current;
                    enum1valid = enum1.MoveNext();
                }
                else if (cmpResult > 0)
                {
                    yield return enum2.Current;
                    enum2valid = enum2.MoveNext();
                }
                else
                {
                    enum1valid = enum1.MoveNext();
                    enum2valid = enum2.MoveNext();
                }
            }
            while (enum1valid)
            {
                yield return enum1.Current;
                enum1valid = enum1.MoveNext();
            }
            while (enum2valid)
            {
                yield return enum2.Current;
                enum2valid = enum2.MoveNext();
            }
        }
    }


    public static IEnumerable<T> SymmetricDifference<T>(IEnumerable<T> coll1, IEnumerable<T> coll2)
    {
        return SymmetricDifference(coll1, coll2, Comparer<T>.Default);
    }

Upvotes: 2

jason
jason

Reputation: 241601

Your question is not completely specified but I assume that you are looking for the differences as sets (that is, ordering does not matter). If so, you want the symmetric difference of the two sets. You can achieve this using Enumerable.Except:

before.Except(after).Union(after.Except(before));

Upvotes: 29

Nigel Touch
Nigel Touch

Reputation: 1956

As an alternative to linq answers, which have to pass both lists twice, use HashSet.SymmetricExceptWith():

var difference = new HashSet(before);
difference.SymmetricExceptWith(after);

Could be considerably more efficient.

Upvotes: 23

Manu
Manu

Reputation: 29143

Another way:

before.Union(after).Except(before.Intersect(after))

Upvotes: 5

Related Questions