7

This is probable a common question, and I have searched other question without finding a solution that works (note, my skill in C# and linq is limited - so a simple solution would be appreciated!).

Here is the issue:

I have 2 lists with objects. I want to compare them and return all the NEW objects in list2.

Example:

ObjectList List1; // contains 3 objects that is stored in the database

ObjectList List2; // contains the same 3 objects as in List1 and a new object that was added from a webpage (the parent object was updated on the webpage)

ObjectList List3; // should do a compare of List1 and List2, and return the NEW objects in List2 (so the result should only be Object number 4)

Note:

  • The order does not matter. I only want the new object(s)
  • Normally objects are only added to List2. IF any object is removed (compare to List1), then this should be ignored. (so object that only exists in List1 is of no interest)

Thanks for any suggestions or links to previously questions i missed in my search

Edit

Here is a small example of first try with Except (this returned an error)

I have shortened it a bit. The method is from our software, so they are probable not know to you. Sorry about that.

 // caDialogObjects = List1 (caDialogQLMLinks is the link to the objects)
RepositoryObjectList caDialogObjects = args.Object.GetConfiguration().GetObjectSet(caDialogQLMLinks);

// caObjectObjects = List2 (caObjectQLMLinks is the link to the objects)
RepositoryObjectList caObjectObjects = args.Object.GetConfiguration().GetObjectSet(caObjectQLMLinks);

// List 3
RepositoryObjectList caTotal;
caTotal = caObjectObjects.Except(caDialogObjects);

Solution that worked The Exception did not work since the list is just a reference (not a value). It is possible to use the second parameter, but i got a linq code that worked:

RepositoryObjectList caNewCA = 
    new RepositoryObjectList(caDialogObjects.Where(item1 => 
         !caObjectObjects.Any(item2 => item1.Id == item2.Id)));
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
Kim
  • 71
  • 1
  • 1
  • 4
  • Possible duplicate of [Difference between two lists](https://stackoverflow.com/questions/5636438/difference-between-two-lists) – JSON Apr 27 '18 at 05:13

4 Answers4

17

Use this:

var list3 = list2.Except(list1);

This uses the Except extension method which returns all elements in list2 that are not in list1.
It is important to note, that Except returns an IEnumerable<T> where T is the type of the object inside list1 and list2.
If you need your list3 to be of a specific type, you need to convert that return value. In the simplest case, your target type has a constructor that can handle and IEnumerable<T>:

RepositoryObjectList list3 = new RepositoryObjectList(list2.Except(list1));
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • I like this better than mine :) – iain May 02 '11 at 12:41
  • It would also be good to mention the [Except overload](http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except.aspx) which uses an `IEqualityComparer` instance to compare the elements. – vgru May 02 '11 at 12:43
  • Hi daniel.Thank you for the answer. This was in fact one of the solution I tried. But I get the error "CAnnot implicitly convert type "RepositoryObject" tog "RepositoryObjectList". These two types are from our software. But All 3 lists are declared as "RepositoryObjectList". – Kim May 02 '11 at 12:43
  • So it might be a problem with my Types. I will look into it. Thanks again – Kim May 02 '11 at 12:44
  • Please show your code. There seems to be an error somewhere when you get that error message. – Daniel Hilgarth May 02 '11 at 12:44
  • I have edit the question with a small sample. Don't know if it is enough. It is a lot of software methode here that may make it difficult. But I will try all the good suggestion here and hopefully I will get it to work. Thanks! – Kim May 02 '11 at 13:05
  • @Daniel Thanks. The code returned no errors. I will try it and updated you later (It might be a few days since I have to work on another project). – Kim May 02 '11 at 13:24
  • @Daniel: This made me laugh for some reason: "There seems to be an error somewhere when you get that error message." – Chris Dunaway May 02 '11 at 14:32
  • @Chris: haha, yeah. That happens, if you can't really explain what is going wrong... :-) – Daniel Hilgarth May 02 '11 at 14:35
  • @Daniel: Thanks, unfortunate List3 is just a copy of List2 (it does not remove those from List1) I will have a meeting with a software expert today and we will look into this. It might be something software specific. I will notify you after the meeting. Again, thanks for the help – Kim May 04 '11 at 06:28
  • @Kim: Most likely, the implementation of the equality comparison of `RepositoryObject` doesn't exist at all or is buggy. The default equality comparison checks for reference equality, not value equality. – Daniel Hilgarth May 04 '11 at 09:30
  • @daniel, all: Thanks for alls suggestions. The Exeption did not work due to the REpositoryObjectList was a collection of reference, and it didn't work. I got some linq code that worked (other solution was to use the second parametre in the Except method). My solution was added to the question abov for other to view... – Kim May 05 '11 at 13:33
4
   List<MyObject> objectList1 = new List<MyObject>();
   List<MyObject> objectList2 = new List<MyObject>();
   List<MyObject> objectList3 = objectList2.Where(o => !objectList1.Contains(o)).ToList();

This should do it, as long as MyObject is IComparable

http://msdn.microsoft.com/en-us/library/system.icomparable.aspx

iain
  • 1,693
  • 13
  • 19
  • +1 For an example that has a list of reference types, instead of simple value types, and for mentioning IComparable. I find almost all lists I work with are of complex reference types so I'm suspicious of solutions that involve only value types. – Simon Elms Jun 19 '16 at 22:23
3

Here's an example of how you could do it using LINQ:

List<int> l1 = new List<int>();
List<int> l2 = new List<int>();

l1.AddRange(new int[] {1, 2, 3, 5});
l2.AddRange(new int[] {1, 2, 3, 4});

// get only the objects that are in l2, but not l1
var l3 = l2.Except(l1);

The third list will only contain one element, 4.

alex
  • 3,710
  • 32
  • 44
1
secondList.Except(firstList)

which uses

public static IEnumerable<TSource> Except<TSource>(
    this IEnumerable<TSource> first,
    IEnumerable<TSource> second
)

http://msdn.microsoft.com/en-us/library/bb300779.aspx

or

secondList.Except(firstList,new CustomComparer())

which uses

public static IEnumerable<TSource> Except<TSource>(
    this IEnumerable<TSource> first,
    IEnumerable<TSource> second,
    IEqualityComparer<TSource> comparer
)

http://msdn.microsoft.com/en-us/library/bb336390.aspx

abhilash
  • 5,605
  • 3
  • 36
  • 59