Functional programming with Linq – Enumerable.SequenceEqual

Yet another useful method on the Enumerable class, the SequenceEqual method does exactly what it says on the tin and tells you whether or not two sequences are of equal length and their corresponding elements are equal according to either the default or supplied equality comparer:

var list1 = new List<int>() {0 ,1 ,2, 3, 4, 5, 6 };
var list2 = new List<int>() {0 ,1 ,2, 3, 4, 5, 6 };
var list3 = new List<int>() {6 ,5 ,4, 3, 2, 1, 0 };

list1.SequenceEqual(list2); // returns true
list1.SequenceEqual(list3); // returns false

As you know, for reference types the default equality comparer compares the reference itself hence:

class Pet
{
    public string Name { get; set; }
    public int Age { get; set; }
}
…
Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet { Name = "Peanut", Age = 8 };

// Create two lists of pets.
var pets1 = new List<Pet> { pet1, pet2 };
var pets2 = new List<Pet> { pet1, pet2 };
var test1 = pets1.SequenceEqual(pets2); // returns true

var pets3 = new List<Pet> { pet1, new Pet { Name = "Peanut", Age = 8 } };
var test2 = pets1.SequenceEqual(pets3); // returns false

There are a number of ways you can get around this, including:

  • make Pet a value type, i.e. struct
  • make Pet implement the IEquatable interface
  • create an EqualityComparer and use the overloaded SequenceEqual method which takes an equality comparer

Here is an interesting usage of the SequenceEqual method to help find duplicates in a list of lists (see this StackOverflow question) as provided by Judah Himango:

var lists = new List<List<int>>()
{
    new List<int>() {0 ,1, 2, 3, 4, 5, 6 },
    new List<int>() {0 ,1, 2, 3, 4, 5, 6 },
    new List<int>() {0 ,1, 4, 2, 4, 5, 6 },
    new List<int>() {0 ,3, 2, 5, 1, 6, 4 }
};

var duplicates = from list in lists
                 where lists.Except(new[] { list }).Any(l => l.SequenceEqual(list))
                 select list;