David's solution has a fundamental inefficiency. It iterates through the
newbooks
collection for each member of
oldbooks
. This makes it
O(n*m) where
n
is the count of
newbooks
and
m
is the count of
oldbooks
.
Your initial attempt with
.Except()
was
almost right!
Using David's Books class as the example:
You needed either to override the Equals() method of Books:
public class Books
{
public string Name { get; set; }
public DateTime PublishDate { get; set; }
public override bool Equals(object obj)
{
Books other = obj as Books;
return other != null && this.PublishDate == other.PublishDate;
}
public override int GetHashCode()
{
return PublishDate.GetHashCode();
}
}
var diff = oldbooks.Except(newbooks);
(If you override
Equals
it is very important to also override
GetHashCode
.)
This means that all comparisons of
Books
objects would consider only the
PublishDate
, and you couldn't do this for a different comparison later.
A more flexible way would be to implement a comparer class:
public class Books
{
public string Name { get; set; }
public DateTime PublishDate { get; set; }
}
public class BooksDateComparer : IEqualityComparer<Books>
{
public bool Equals(Books x, Books y)
{
if (Object.ReferenceEquals(x, y))
return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.PublishDate == y.PublishDate;
}
public int GetHashCode(Books obj)
{
if (Object.ReferenceEquals(obj, null))
return 0;
return obj.PublishDate.GetHashCode();
}
}
var diff = oldbooks.Except(newbooks, new BooksDateComparer());
Also, just for clarification: Linq works
exactly the same on arrays as it does on
List<T>
. It only needs the collection to implement
IEnumerable<T>
.