Iofacture
Iofacture

Reputation: 685

LINQ Compare two lists where property value is not equal

I have been over a few StackOverflow articles about this (this in particular) and for some reason my case is different. I've used Tony the Lion's answer to attempt to get a list of objects that have different property values, without success. This, however does work:

List<Task> changedTasksWorking = new List<Task>();
for (int x = 0; x < originalTaskList.Count; x++)
{
    if (originalTaskList[x].ActiveFlag != newTaskList[x].ActiveFlag)
    {
        changedTasksWorking.Add(newTaskList[x]);
    }
}

The following is what I thought would provide me the same result. But where the returned list should equal 1, it instead equals zero. When I flip the property comparison to != and remove the nor condition on the inner list, I get ALL the objects of the list instead:

List<Task> notWork = oL.Where(o => newL.Any(n => o.ActiveFlag != n.ActiveFlag)).ToList();

I feel like I'm taking crazy pills. Looking at the above one-liner that should give me what I'm asking for. Perhaps I have misunderstood how the LINQ methods Where and Any are interacting.

Upvotes: 2

Views: 2804

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70652

Your proposed LINQ approach is completely different from what you seem to actually be trying to do. In particular, according to your original example, you have two lists that are exactly in sync with each other. I.e. they have the same number of elements, and each element from one list corresponds exactly to the same element in the same position in the other list.

Your LINQ code, on the other hand, looks at each element in one list at a time, and for each of those elements, searches the other list for one that has a property value that doesn't match. In other words, if the newL list has elements of all possible values of ActiveFlag then of course it will return all elements of oL, because for each element in oL, LINQ is able to find an element in newL where the property value doesn't match.

There are at least a couple of obvious alternatives using LINQ that will actually work:

  1. Use the overload for Where() that passes the index to the predicate delegate:
List<Task> changedTasks = newTaskList
    .Where((n, i) => n.ActiveFlag != originalTaskList[i].ActiveFlag).ToList();
  1. Use Enumerable.Zip() to pair up elements in a new sequence and filter that:
List<Task> changedTasks = originalTaskList
    .Zip(newTaskList, (o, n) => o.ActiveFlag != n.ActiveFlag ? n : null)
    .Where(n => n != null).ToList();

Either of those should work fine.

Upvotes: 5

Related Questions