C#

[C#]HashSet 특정 값이 존재하는지 확인하는 방법

DevStory 2022. 8. 21.

HashSet 특정 값이 존재하는지 확인하는 방법

HashSet은 중복되지 않은 값들이 존재하는 데이터 집합입니다.

 

다음 예제에서 확인할 수 있듯이 HashSet 객체를 초기화할 때, 동일한 값인 3을 4번 할당했지만 단 하나의 값만 할당되었습니다.

 

즉, 이미 존재하는 값은 추가되지 않습니다.

class Program
{
  static void Main(string[] args)
  {
    HashSet<int> hs = new HashSet<int>()
    {
      3, 3, 3, 3 
    };

    Console.WriteLine("hs.Count: " + hs.Count);

    Console.WriteLine("\n[hs의 요소]");
    foreach (int item in hs)
    {
      Console.Write(item + " ");
    }
  }
}

[실행 결과]

hs.Count: 1

[hs의 요소]
3

하지만, 다음 예제처럼 HashSet의 데이터 타입이 사용자가 정의한 클래스인 경우 중복된 값이 할당됩니다.

 

객체의 프로퍼티를 비교하는 것이 아니라 참조 값을 비교하기 때문에 다른 값으로 판단합니다.

public class Person
{
  public string Name { get; set; }
  public int Age { get; set; }        
}

class Program
{
  static void Main(string[] args)
  {
    HashSet<Person> hs = new HashSet<Person>()
    {
      new Person(){Name="둘리", Age=20},
      new Person(){Name="둘리", Age=20},
      new Person(){Name="둘리", Age=20}
    };

    Console.WriteLine("hs.Count: " + hs.Count);

    Console.WriteLine("\n[hs의 요소]");
    foreach (Person item in hs)
    {
      Console.WriteLine("Name: " + item.Name + ", Age: " + item.Age);
    }
  }
}

[실행 결과]

hs.Count: 3

[hs의 요소]
Name: 둘리, Age: 20
Name: 둘리, Age: 20
Name: 둘리, Age: 20

이번 포스팅은 HashSet의 데이터가 기본 타입 또는 사용자가 정의한 클래스 타입인 경우 특정 값이 존재하는지 확인할 수 있는 몇 가지 방법을 소개합니다.


방법 1. 반복문

가장 심플한 방법으로 반복문을 사용합니다.

 

다음 예제는 HashSet에 특정 값이 존재하는지 확인하는 isHasValue() 메서드를 정의하였으며, 특정 값이 존재하면 true를 반환하고 그렇지 않으면 false를 반환합니다.

class Program
{
  public static bool isHasValue<T>(HashSet<T> hs, T val)
  {
    foreach (T item in hs)
    {
      if (item.Equals(val)) return true;
    }
    return false;
  }

  static void Main(string[] args)
  {
    HashSet<int> hs = new HashSet<int>()
    {
      100, 200, 300
    };

    Console.WriteLine("HashSet에 100이 존재하는가? " + isHasValue(hs, 100));
    Console.WriteLine("HashSet에 200이 존재하는가? " + isHasValue(hs, 200));
    Console.WriteLine("HashSet에 500이 존재하는가? " + isHasValue(hs, 500));
  }
}

[실행 결과]

HashSet에 100이 존재하는가? True
HashSet에 200이 존재하는가? True
HashSet에 500이 존재하는가? False

방법 2. HashSet 클래스의 Contains 메서드

두 번째 방법으로 HashSet 클래스에서 제공하는 Contains() 메서드를 사용합니다.

public bool Contains(T item);

HashSet 객체에서 Contains() 메서드를 호출하고 특정 값을 매개변수로 전달합니다.

 

특정 값이 존재하면 true를 반환하고 그렇지 않으면 false를 반환합니다.


예제 1. 기본 타입

다음 예제는 int 타입의 HashSet에서 특정 값이 존재하는지 Contains() 메서드로 확인합니다.

class Program
{
  static void Main(string[] args)
  {
    HashSet<int> hs = new HashSet<int>()
    {
      100, 200, 300
    };

    Console.WriteLine("HashSet에 100이 존재하는가? " + hs.Contains(100));
    Console.WriteLine("HashSet에 200이 존재하는가? " + hs.Contains(200));
    Console.WriteLine("HashSet에 500이 존재하는가? " + hs.Contains(500));
  }
}

[실행 결과]

HashSet에 100이 존재하는가? True
HashSet에 200이 존재하는가? True
HashSet에 500이 존재하는가? False

예제 2. 사용자가 정의한 클래스 타입

맨 위에서 언급했듯이 HashSet의 데이터가 사용자가 정의한 클래스 타입인 경우 참조 값을 비교합니다.

 

그렇기 때문에 다음 예제처럼 Contains() 메서드에 객체를 전달하는 경우 다른 값으로 판단합니다.

public class Person
{
  public string Name { get; set; }
  public int Age { get; set; }        
}

class Program
{
  static void Main(string[] args)
  {
    HashSet<Person> hs = new HashSet<Person>()
    {
      new Person(){Name="둘리", Age=20}
    };

    Console.WriteLine("HashSet에 {Name=\"둘리\", Age=20}이 존재하는가? "
        + hs.Contains(new Person() { Name = "둘리", Age = 20 }));
  }
}

[실행 결과]

HashSet에 {Name="둘리", Age=20}이 존재하는가? False

참조 값이 아닌 프로퍼티의 값을 비교하도록 Person 클래스에서 Equals() 메서드와 GetHashCode() 메서드를 재정의합니다.

 

Equals() 메서드와 GetHashCode() 메서드를 재정의하면 중복되는 객체가 HashSet에 할당되지 않고 Contains() 메서드는 참조 값이 아닌 프로퍼티 값으로 데이터를 비교합니다.

 

다음 예제는 Person 클래스의 Equals() 메서드와 GetHashCode() 메서드를 재정의 후 Contains() 메서드를 호출합니다.

public class Person
{
  public string Name { get; set; }
  public int Age { get; set; }

  public override bool Equals(object x)
  {
    return this.Name == ((Person)x).Name && this.Age == ((Person)x).Age;
  }

  public override int GetHashCode()
  {
    return this.Name.GetHashCode() ^ this.Age.GetHashCode();
  }
}

class Program
{
  static void Main(string[] args)
  {
    HashSet<Person> hs = new HashSet<Person>()
    {
      new Person(){Name="둘리", Age=20},
      new Person(){Name="둘리", Age=20},
      new Person(){Name="둘리", Age=20}
    };

    Console.WriteLine("HashSet에 {Name=\"둘리\", Age=20}이 존재하는가? "
        + hs.Contains(new Person() { Name = "둘리", Age = 20 }));

    Console.WriteLine("\n[hs의 요소]");
    foreach (Person item in hs)
    {
      Console.WriteLine("Name: " + item.Name + ", Age: " + item.Age);
    }

    Console.WriteLine("\nhs.Count: " + hs.Count);
  }
}

[실행 결과]

HashSet에 {Name="둘리", Age=20}이 존재하는가? True

[hs의 요소]
Name: 둘리, Age: 20

hs.Count: 1

방법 2. LINQ의 Any 메서드

마지막 방법으로 LINQ에서 제공하는 Any() 메서드를 사용하는 방법입니다.

 

Any() 메서드는 배열 또는 컬렉션과 같은 데이터 집합에서 특정 조건을 만족하는 데이터가 있으면 true를 반환하고 그렇지 않으면 false를 반환합니다.

 

먼저, LINQ에서 제공하는 기능을 사용하기 위해 다음 네임스페이스를 추가합니다. 

using System.Linq;

Any() 메서드의 장점은 특정 값뿐만 아니라 특정 조건을 만족하는 값이 있는지 확인할 수 있습니다.


예제 1. 특정 값이 존재하는지

다음 예제는 int 타입의 HashSet에서 Any() 메서드를 사용하여 특정 값이 존재하는지 확인합니다.

class Program
{
  static void Main(string[] args)
  {
    HashSet<int> hs = new HashSet<int>()
    {
      10, 20, 30, 40, 50
    };

    Console.WriteLine("HashSet에 10이 존재하는가? " + 
        hs.Any(item => item.Equals(10)));

    Console.WriteLine("HashSet에 20이 존재하는가? " +
        hs.Any(item => item.Equals(20)));

    Console.WriteLine("HashSet에 70이 존재하는가? " +
        hs.Any(item => item.Equals(70)));
  }
}

[실행 결과]

HashSet에 10이 존재하는가? True
HashSet에 20이 존재하는가? True
HashSet에 70이 존재하는가? False

예제 2. 특정 조건을 만족하는지

다음 예제는 HashSet에서 40보다 큰 값이 존재하는지 확인합니다.

class Program
{
  static void Main(string[] args)
  {
    HashSet<int> hs = new HashSet<int>()
    {
      10, 20, 30, 40, 50
    };

    Console.WriteLine("HashSet에 40보다 큰 값이 존재하는가? " + 
        hs.Any(item => item > 40));
  }
}

[실행 결과]

HashSet에 40보다 큰 값이 존재하는가? True
반응형

댓글