CodeGym /행동 /C# SELF /C#에서 컬렉션에서 요소 찾기

C#에서 컬렉션에서 요소 찾기

C# SELF
레벨 29 , 레슨 1
사용 가능

1. 컬렉션에서 기본적인 검색 기능

보통 “검색”이랑 “필터링”을 비슷하게 생각하는데, 프로그래밍에서는 좀 달라.

  • 필터링 — 컬렉션에서 어떤 조건에 맞는 모든 요소를 뽑아내는 거야 (예: 10보다 큰 모든 숫자).
  • 검색 — 보통 한 개의 요소만 찾거나, 특정 값이 있는지 확인하거나, 첫 번째로 맞는 것만 찾는 거지.

도서관에 비유하면: 필터링은 “우주” 주제의 모든 책을 모으는 거고, 검색은 “‘율리시스’라는 책 있어요?” 또는 “파란색 표지의 첫 번째 책이 어디 있어요?”라고 묻는 거랑 비슷해.

.NET의 모든 주요 컬렉션(배열, 리스트, 집합, 딕셔너리 등)은 요소를 찾거나 존재 여부를 확인하는 여러 방법을 지원해.

가장 많이 쓰는 메서드들을 살펴보자:

컬렉션 존재 확인 인덱스 찾기 요소 찾기 키로 찾기
List<T>
Contains
IndexOf
Find
-
T[]
(배열)
Contains
/
Array.IndexOf
Array.IndexOf
- -
HashSet<T>
Contains
- - -
Dictionary<TKey,V>
ContainsKey
,
ContainsValue
- - 인덱서
[key]
있음

어떤 메서드는 특정 타입에서만 쓸 수 있어.

2. 리스트에서 찾기: List<T>

List<T>는 임의 접근이 가능한 가장 범용적인 컬렉션 중 하나야. 주요 검색 메서드는 이래:

요소 존재 확인: Contains

이 메서드는 리스트에 원하는 요소가 있는지 알려줘:

List<string> fruits = new List<string> { "사과", "바나나", "키위" };
bool hasKiwi = fruits.Contains("키위"); // true
bool hasMango = fruits.Contains("망고"); // false
Console.WriteLine(hasKiwi); // True

Contains는 내부적으로 Equals로 컬렉션을 순회해.

인덱스 찾기: IndexOf

요소가 리스트에서 어디에 있는지(몇 번째인지) 알고 싶으면:

int index = fruits.IndexOf("바나나"); // 1 (0부터 시작)
int absentIndex = fruits.IndexOf("수박"); // -1 (없으면)
Console.WriteLine(index);
Console.WriteLine(absentIndex);

첫 번째로 맞는 것 찾기: Find

정확한 값이 아니라 조건으로 찾고 싶으면 Find (혹은 인덱스가 필요하면 FindIndex)를 써:

// 이름이 4글자보다 긴 첫 번째 과일 찾기
string longFruit = fruits.Find(fruit => fruit.Length > 4); // "사과"
Console.WriteLine(longFruit);

참고: 못 찾으면 타입의 기본값을 반환해(참조형이면 null).

여러 개 찾기(필터링): FindAll

필터링(조건에 맞는 모든 것)이 필요하면 FindAll을 써:

// 이름에 '이'가 들어간 모든 과일
List<string> withI = fruits.FindAll(f => f.Contains('이'));
foreach (var fruit in withI)
    Console.WriteLine(fruit); // "키위"

3. 배열에서 찾기: Array 클래스 메서드

배열은 Find 같은 메서드가 없지만, List<T>처럼 쓸 수 있는 정적 클래스 Array가 있어:

int[] numbers = { 1, 2, 3, 2, 4 };
int pos = Array.IndexOf(numbers, 2); // 1 — 첫 번째 2의 인덱스
int lastPos = Array.LastIndexOf(numbers, 2); // 3 — 마지막 2의 인덱스
Console.WriteLine(pos + ", " + lastPos);

조건으로 찾으려면 그냥 for문 쓰면 돼:

int firstGreaterThanTwo = -1;
for (int i = 0; i < numbers.Length; i++)
{
    if (numbers[i] > 2)
    {
        firstGreaterThanTwo = numbers[i];
        break;
    }
}
Console.WriteLine(firstGreaterThanTwo); // 3

4. 모든 컬렉션에서 쓸 수 있는 방법

많은 컬렉션이 Contains, IndexOf, Find 같은 메서드를 제공해. 더 복잡한 게 필요하면 직접 for문으로 순회하면 돼.

예시: "ㅂ"으로 시작하는 과일이 있는지 확인

bool hasB = false;
foreach (var f in fruits)
{
    if (f.StartsWith("바"))
    {
        hasB = true;
        break;
    }
}
Console.WriteLine(hasB); // True

예시: "이"가 들어간 첫 번째 과일 찾기

string withI = null;
foreach (var f in fruits)
{
    if (f.Contains('이'))
    {
        withI = f;
        break;
    }
}
Console.WriteLine(withI); // "키위"

예시: 사용자 객체에서 찾기

class Student
{
    public string Name;
    public int Group;
    public int Id;
}

List<Student> students = new List<Student>
{
    new Student { Name = "이반", Group = 101, Id = 1 },
    new Student { Name = "마리야", Group = 101, Id = 2 },
    new Student { Name = "표트르", Group = 102, Id = 3 },
};

// Id == 2인 학생 찾기
Student maria = null;
foreach (var s in students)
{
    if (s.Id == 2)
    {
        maria = s;
        break;
    }
}
if (maria != null)
    Console.WriteLine(maria.Name); // "마리야"
else
    Console.WriteLine("학생을 찾을 수 없음");

5. HashSet<T>에서 찾기: “있냐 없냐”만!

집합(HashSet<T>)은 “이거 있냐?”를 엄청 빠르게 확인하려고 만든 거야. 인덱스로 찾는 건 안 되지만, 존재 여부는 진짜 빨라:

HashSet<int> set = new HashSet<int> { 1, 3, 5, 7 };
bool hasThree = set.Contains(3); // True
Console.WriteLine(hasThree);

// 조건으로 찾으려면(예: 짝수 있는지):
bool hasEven = false;
foreach (var x in set)
{
    if (x % 2 == 0)
    {
        hasEven = true;
        break;
    }
}
Console.WriteLine(hasEven); // False

6. 딕셔너리에서 찾기: Dictionary<TKey, TValue>

딕셔너리는 “키-값” 쌍의 컬렉션이야. 키로 찾는 게 진짜 강점이지.

키 존재 확인

Dictionary<int, string> idToName = new Dictionary<int, string>
{
    { 1, "바샤" }, { 2, "카탸" }
};
if (idToName.ContainsKey(2))
    Console.WriteLine(idToName[2]); // "카탸"

키로 값 찾기: 안전하게!

if (idToName.TryGetValue(3, out string result))
    Console.WriteLine(result);
else
    Console.WriteLine("그런 Id의 학생 없음"); // 이게 출력됨

값으로 찾기(잘 안 쓰고 느림):

bool containsVasya = idToName.ContainsValue("바샤");
Console.WriteLine(containsVasya); // True

값이나 키 조건으로 찾기

// 이름이 "카"로 시작하는 첫 번째 Id 찾기
KeyValuePair<int, string> entry = default;
bool found = false;
foreach (var pair in idToName)
{
    if (pair.Value.StartsWith("카"))
    {
        entry = pair;
        found = true;
        break;
    }
}
if (found)
    Console.WriteLine($"{entry.Key}: {entry.Value}"); // "2: 카탸"

7. 유용한 팁

검색 메서드 표

컬렉션 타입 존재 확인 Contains 인덱스 찾기 IndexOf 조건으로 찾기 Find 키로 안전하게 찾기 TryGetValue
List<T>
네 (
Find
)
-
T[]
(배열)
네 (
Array.Contains
/for문)
네 (
Array.IndexOf
)
for문 -
HashSet<T>
- 아니(직접 해야 함) -
Dictionary<TKey,V>
네 (
ContainsKey
)
- 직접 키/값으로

직접 for문으로 찾기

완전히 이해하려면 직접 컬렉션에서 찾는 메서드를 만들어보자. 예를 들어, 지정한 값보다 큰 첫 번째 요소의 인덱스를 찾는 함수:

static int FindFirstGreaterIndex(IEnumerable<int> collection, int minValue)
{
    int index = 0;
    foreach (var item in collection)
    {
        if (item > minValue)
            return index;
        index++;
    }
    return -1; // 못 찾음
}

var nums = new List<int> { 1, 4, 7, 2 };
Console.WriteLine(FindFirstGreaterIndex(nums, 3)); // 1 (숫자 4)

여기서는 (List<T>, int[], HashSet<T> 등) 타입이나 내부 구현에 상관없이 쓸 수 있어.

실제 문제에서 검색 활용 예시

  • DB에서 로그인이나 이메일로 사용자 찾기.
  • 장바구니에 상품이 있는지 확인.
  • 설정값을 이름으로 빠르게 찾기.
  • 특정 단계가 이미 실행됐는지 확인(workflow 등).
  • 로그 배열에서 에러 위치 찾기.

미들급 개발자 면접에서는 꼭 이런 질문 나와: “컬렉션에서 요소를 어떻게 찾나요? 조건에 맞는 첫 번째/모든/인덱스 반환하는 메서드를 어떻게 만들 거예요?” 연습 많이 해두면 좋아!

8. 검색할 때 흔히 하는 실수와 특징

중요한 점: 검색 메서드는 객체 비교 방식에 따라 달라져. 예를 들어, 리스트에 직접 만든 클래스를 넣으면 기본 비교는 “참조” 비교야! “내용”으로 검색하려면 EqualsGetHashCode를 오버라이드해야 해(이건 다음 강의에서 더 자세히 다룰게).

문제 예시:

var s1 = new Student { Name = "예고르", Id = 42 };
students.Add(s1);
// 이제 같은 Id와 이름으로 새 객체 생성:
var s2 = new Student { Name = "예고르", Id = 42 };
Console.WriteLine(students.Contains(s2)); // False (!)

컴파일러는 필드가 아니라 참조로 비교해서(다른 객체라서 그래).

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION