C#에서 HashSet<T> 컬렉션의 요소를 차례대로 순회하는 열거자(Enumerator)를 얻으려면 GetEnumerator() 메서드를 사용하면 됩니다. 이 메서드는 HashSet<T>.Enumerator 형식의 열거자를 반환하며, MoveNext()로 다음 요소로 이동하고 Current 속성으로 현재 요소를 읽어오는 방식으로 동작합니다.
핵심 동작 방식
- GetEnumerator() : HashSet을 순회할 수 있는 열거자 객체를 반환합니다.
- MoveNext() : 다음 요소로 커서를 이동하며, 더 이상 요소가 없으면 false를 반환합니다.
- Current : 현재 위치의 요소를 반환합니다.
한 가지 참고할 점은 HashSet이 중복 값을 자동으로 제거하며 저장 순서를 보장하지 않는다는 것입니다. 아래 두 번째 예제에서 이 특성을 직접 확인할 수 있습니다.
예제 1
using System;
using System.Collections.Generic;
public class Demo {
public static void Main(String[] args) {
HashSet<string> set1 = new HashSet<string>();
set1.Add("A");
set1.Add("B");
set1.Add("C");
set1.Add("D");
set1.Add("E");
set1.Add("F");
set1.Add("G");
set1.Add("H");
Console.WriteLine("HashSet1의 요소...");
foreach (string res in set1) {
Console.WriteLine(res);
}
HashSet<string> set2 = new HashSet<string>();
set2.Add("John");
set2.Add("Jacob");
set2.Add("Ryan");
set2.Add("Tom");
set2.Add("Andy");
set2.Add("Tim");
set2.Add("Steve");
set2.Add("Mark");
Console.WriteLine("HashSet2의 요소... (열거자로 HashSet 순회)");
HashSet<string>.Enumerator demoEnum = set2.GetEnumerator();
while (demoEnum.MoveNext()) {
string res = demoEnum.Current;
Console.WriteLine(res);
}
Console.WriteLine("HashSet1과 HashSet2가 같은가? = " + set1.Equals(set2));
Console.WriteLine("HashSet2의 요소 개수 = " + set2.Count);
set2.Clear();
Console.WriteLine("HashSet2의 요소 개수 (갱신 후) = " + set2.Count);
}
}출력 결과
HashSet1의 요소... A B C D E F G H HashSet2의 요소... (열거자로 HashSet 순회) John Jacob Ryan Tom Andy Tim Steve Mark HashSet1과 HashSet2가 같은가? = False HashSet2의 요소 개수 = 8 HashSet2의 요소 개수 (갱신 후) = 0
위 예제의 핵심은 HashSet<string>.Enumerator demoEnum = set2.GetEnumerator(); 부분입니다. 열거자를 명시적으로 선언한 뒤 while 루프에서 MoveNext()와 Current를 조합해 모든 요소를 순회했습니다. 또한 Clear() 호출 후 Count가 8에서 0으로 변경되는 것도 확인할 수 있습니다.
예제 2
이번에는 중복 값 추가 시 HashSet의 동작과 IsSupersetOf() 메서드까지 함께 살펴보겠습니다.
using System;
using System.Collections.Generic;
public class Demo {
public static void Main() {
HashSet<string> set1 = new HashSet<string>();
set1.Add("AB");
set1.Add("CD");
set1.Add("EF");
set1.Add("AB"); // 중복 값
set1.Add("IJ");
set1.Add("KL");
set1.Add("EF"); // 중복 값
set1.Add("OP");
Console.WriteLine("HashSet1의 요소");
foreach (string val in set1) {
Console.WriteLine(val);
}
HashSet<string> set2 = new HashSet<string>();
set2.Add("EF");
set2.Add("KL");
Console.WriteLine("HashSet2의 요소... (열거자로 HashSet 순회)");
HashSet<string>.Enumerator demoEnum = set2.GetEnumerator();
while (demoEnum.MoveNext()) {
string res = demoEnum.Current;
Console.WriteLine(res);
}
Console.WriteLine("set1은 set2의 상위 집합인가? " + set1.IsSupersetOf(set2));
}
}출력 결과
HashSet1의 요소 AB CD EF IJ KL OP HashSet2의 요소... (열거자로 HashSet 순회) EF KL set1은 set2의 상위 집합인가? True
실행 결과를 보면 "AB"와 "EF"를 두 번 추가했음에도 각각 한 번만 저장된 것을 알 수 있습니다. 이는 HashSet이 고유한 값만 유지하기 때문입니다. 또한 set1이 set2의 모든 요소(EF, KL)를 포함하고 있으므로 IsSupersetOf()는 true를 반환합니다.
정리
대부분의 경우 foreach 문만으로 충분하지만, 커스텀 순회 로직이나 세밀한 제어가 필요한 상황에서는 위와 같이 GetEnumerator(), MoveNext(), Current를 직접 활용하면 됩니다.