C#/LINQ

[C#]LINQ 두 데이터가 동일한지 체크 - SequenceEqual 메서드

DevStory 2022. 8. 9.

SequenceEqual 메서드

C#의 Linq는 두 개의 시퀀스를 비교하는 SequenceEqual() 메서드를 제공합니다. 두 시퀀스가 동일하면 true를 반환하고 그렇지 않으면 false를 반환합니다.

 

SequenceEqual() 메서드는 두 시퀀스에 동일한 수의 데이터가 존재하고 동일한 순서로 정렬되어 있는 경우 동일한 것으로 간주하고 true를 반환합니다.

 

System.Linq 네임스페이스에 존재하는 SequenceEqual() 메서드는 두 가지 오버로드된 버전이 존재합니다.

public static bool SequenceEqual<TSource>(
  this IEnumerable<TSource> first, 
  IEnumerable<TSource> second);

public static bool SequenceEqual<TSource>(
  this IEnumerable<TSource> first, 
  IEnumerable<TSource> second, 
  IEqualityComparer<TSource> comparer);

두 번째 SequenceEqual() 메서드는 IEqualityComparer 타입의 매개변수가 존재합니다. 따라서, 두 시퀀스의 데이터를 비교하는 기준을 정의할 수 있습니다.


예제 1. int 타입의 List 비교

다음 예제는 int 타입인 두 개의 List가 존재합니다. List에는 동일한 수의 데이터가 동일한 순서로 정렬되어 있습니다. 따라서, SequenceEqual() 메서드는 true를 반환합니다.

class Program
{
  static void Main(string[] args)
  {
    List<int> numList1 = new List<int>()
    { 10, 20, 30 };

    List<int> numList2 = new List<int>()
    { 10, 20, 30 } ;

    bool isSequenceEqual = numList1.SequenceEqual(numList2);

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

True

예제 2. 정렬되지 않은 경우

다음 예제처럼 List에 동일한 데이터가 존재하지만, 정렬되어 있지 않은 경우 SequenceEqual 메서드는 false를 반환합니다.

class Program
{
  static void Main(string[] args)
  {
    List<int> numList1 = new List<int>()
    { 10, 20, 30 };

    List<int> numList2 = new List<int>()
    { 30, 20, 10 } ;

    bool isSequenceEqual = numList1.SequenceEqual(numList2);

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

False

예제 3. 정렬 후 비교

두 개의 데이터 집합이 동일한 데이터를 가지고 있지만, 정렬되어 있지 않은 경우 Linq에서 제공하는 OrderBy() 메서드를 사용하여 데이터 정렬 후 SequenceEqual() 메서드를 호출합니다.

 

다음 예제는 numList2에서 OrderBy() 메서드를 호출하여 오름차순으로 정렬된 결과를 SequenceEqual() 메서드에 전달합니다.

class Program
{
  static void Main(string[] args)
  {
    List<int> numList1 = new List<int>()
    { 10, 20, 30 };

    List<int> numList2 = new List<int>()
    { 30, 20, 10 };

    bool isSequenceEqual = numList1.SequenceEqual(numList2.OrderBy(num => num));

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

True

예제 4. string 타입의 List 비교

다음 예제는 string 타입의 List를 비교합니다. 소스 코드에서 볼 수 있듯이 첫 번째 List는 문자열이 대문자로 설정되어 있으며, 두 번째 List는 문자열이 소문자로 설정되어 있습니다.

 

SequenceEqual() 메서드에서 사용되는 기본 비교자는 대문자와 소문자를 구분하므로 False를 반환합니다.

class Program
{
  static void Main(string[] args)
  {
    List<string> strList1 = new List<string>()
    { "ONE", "TWO", "THREE" };

    List<string> strList2 = new List<string>()
    { "one", "two", "three" };

    bool isSequenceEqual = strList1.SequenceEqual(strList2);

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

False
반응형

예제 5. 대소문자 구분 없이 string 타입의 List 비교

대소문자 구분 없이 string 타입의 List를 비교하고 싶은 경우 IEqualityComparer를 매개변수로 가지는 SequenceEqual() 메서드를 사용합니다.

 

다음 예제는 대소문자 구분 없이 문자열을 비교합니다.

class Program
{
  static void Main(string[] args)
  {
    List<string> strList1 = new List<string>()
    { "ONE", "TWO", "THREE" };

    List<string> strList2 = new List<string>()
    { "one", "two", "three" };

    bool isSequenceEqual = strList1.SequenceEqual(strList2, StringComparer.OrdinalIgnoreCase);

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

True

예제 6. 사용자 정의 클래스

다음 예제는 사용자가 정의한 Employee 클래스의 List를 SequenceEqual() 메서드로 비교합니다.

public class Employee
{
  public string Emp_Code { get; set; }
  public string Emp_Name { get; set; }
}

class Program
{
  static void Main(string[] args)
  {
    List <Employee> empList1 = new List<Employee>()
    { 
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" } 
    };

    List <Employee> empList2 = new List<Employee>()
    {
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" }
    };

    bool isSequenceEqual = empList1.SequenceEqual(empList2);

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

False

Employee 타입인 empList1, empList2는 동일한 데이터를 가지고 있지만, SequelceEqual() 메서드는 false를 반환했습니다. 클래스와 같은 복합 타입을 비교할 때, SequenceEqual() 메서드는 객체의 값이 아닌 객체의 참조 값을 비교하기 때문입니다.

 

위 문제를 해결하기 위해서는 다음 세 가지 방법을 사용할 수 있습니다.

1. IEqualityComparer 인터페이스를 구현 클래스를 정의하고 해당 인스턴스를 SequenceEqual() 메서드에 전달합니다.

2. Linq의 기능을 활용하여 익명 타입으로 값을 비교합니다.

3. Student 클래스에서 Equals() 및 GetHashCode() 메서드를 재정의합니다.

 


예제 7. IEqualityComparer 인터페이스 구현

IEqualityComparer 인터페이스 구현 클래스를 정의합니다. EmployeeComparer 클래스는 Employee 클래스의 Emp_Code 프로퍼티와 Emp_Name 프로퍼티의 값을 비교하는 Equals() 메서드와 GetHashCode() 메서드가 존재합니다.

 

다음 예제는 EmployeeComparer 클래스의 객체를 SequenceEqual() 메서드의 두 번째 매개변수로 전달합니다.

public class Employee
{
  public string Emp_Code { get; set; }
  public string Emp_Name { get; set; }
}

public class EmployeeComparer : IEqualityComparer<Employee>
{
  public bool Equals(Employee x, Employee y)
  {
    return x.Emp_Code == y.Emp_Code && x.Emp_Name == y.Emp_Name;
  }

  public int GetHashCode(Employee obj)
  {
    return obj.Emp_Code.GetHashCode() ^ obj.Emp_Name.GetHashCode();
  }
}

class Program
{
  static void Main(string[] args)
  {
    List <Employee> empList1 = new List<Employee>()
    { 
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" } 
    };

    List <Employee> empList2 = new List<Employee>()
    {
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" }
    };

    EmployeeComparer employeeComparer = new EmployeeComparer();

    bool isSequenceEqual = empList1.SequenceEqual(empList2, employeeComparer);

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

True

예제 8. 익명 타입으로 값을 비교

다음 예제는 Linq의 Select() 메서드를 사용하여 익명 타입의 값을 비교합니다.

public class Employee
{
  public string Emp_Code { get; set; }
  public string Emp_Name { get; set; }
}

class Program
{
  static void Main(string[] args)
  {
    List <Employee> empList1 = new List<Employee>()
    { 
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" } 
    };

    List <Employee> empList2 = new List<Employee>()
    {
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" }
    };

    EmployeeComparer employeeComparer = new EmployeeComparer();

    bool isSequenceEqual = empList1.Select(emp => new { emp.Emp_Code, emp.Emp_Name })
            .SequenceEqual(empList2.Select(emp => new { emp.Emp_Code, emp.Emp_Name }));

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

True

예제 9. Equals 및 GetHashCode 메서드 재정의

다음 예제는 Employee 클래스에서 Equals() 및 GetHashCode() 메서드를 재정의합니다.

public class Employee
{
  public string Emp_Code { get; set; }
  public string Emp_Name { get; set; }

  public override bool Equals(object x)
  {
    return this.Emp_Code == ((Employee)x).Emp_Code && this.Emp_Name == ((Employee)x).Emp_Name;
  }

  public override int GetHashCode()
  {
    return this.Emp_Code.GetHashCode() ^ this.Emp_Name.GetHashCode();
  }
}

class Program
{
  static void Main(string[] args)
  {
    List <Employee> empList1 = new List<Employee>()
    { 
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" } 
    };

    List <Employee> empList2 = new List<Employee>()
    {
      new Employee(){ Emp_Code = "100", Emp_Name = "고길동" }
    };

    bool isSequenceEqual = empList1.SequenceEqual(empList2);

    Console.WriteLine(isSequenceEqual);
  }
}

[실행 결과]

True
반응형

댓글