C# 에서 Dictionary는 대괄호 [ ] 기호를 사용해 값을 가져오기 때문에 얼핏 보면 배열처럼 보입니다.
그래서 처음에는 for (int i = 0; i < dict.Count; i++) 같은 방식으로 순회하려는 실수를 하게 됩니다.
하지만 아래 코드를 보면, 배열처럼 접근하는 것이 왜 문제가 되는지 쉽게 이해할 수 있습니다.
실행시 오류가 나는 코드
Dictionary<int, string> numbers = new Dictionary<int, string>()
{
{ 1, "one" },
{ 20, "twenty" },
{ 3, "three" },
{ 19, "nineteen" },
{ 5, "five" },
};
for (int i = 0; i < numbers.Count; i++)
{
if (numbers[i] == "five")
{
Console.WriteLine(numbers[i]);
break;
}
Console.WriteLine(numbers[i]);
}
이 코드는 실행과 동시에 다음과 같은 예외를 발생시킵니다
The given key '0' was not present in the dictionary.
즉, numbers[0] 이라는 키가 존재하지 않기 때문에 런타임 오류가 발생하는 것입니다.
Dictionary는 배열이 아닙니다
Dictionary 는 배열처럼 보이지만, 실제로는 해시 테이블 기반의 자료구조입니다.
즉, numbers[0] 은 0번째 값이 아니라, 키가 0인 데이터를 찾는 것 입니다.
위 코드에서 numbers에는 다음과 같은 키만 존재합니다
1, 20, 3, 19, 5
그렇기 때문에 numbers[0] 이나 numbers[4] 같은 접근은 오류를 일으키게 됩니다.
이처럼 Dictionary[key] 문법은 배열처럼 보이지만, 내부적으로는 this[key]라는 인덱서(Indexer) 기능을 사용한 것입니다.
모양만 비슷할 뿐, 동작 방식은 완전히 다르다는 점을 기억해야 합니다.
Dictionary 순회는 foreach로
Dictionary를 순회할 때는 for 문보다는 foreach 문이 훨씬 더 적합합니다.
for (int i = 0; i < dict.Count; i++)처럼 정수 인덱스를 사용하는 방식은 키가 연속된 정수가 아닌 이상 오류를 유발하기 때문에 권장되지 않는 방법입니다.
올바른 순회 방식은 아래와 같습니다:
foreach (var pair in numbers)
{
Console.WriteLine(pair.Key + " : " + pair.Value);
}
또는 다음과 같이 key 컬렉션을 활용할 수도 있습니다:
foreach (var key in numbers.Keys)
{
Console.WriteLine(key + " : " + numbers[key]);
}
순서가 보장되지 않는 이유
Dictionary는 빠른 검색을 목적으로 만들어진 자료구조이기 때문에 내부 저장 구조가 순차적이거나 정렬된 상태를 유지하지 않습니다.
예를 들어, 입력한 순서가
{ 1, "one" }, { 3, "three" }, { 5, "five" }
이더라도 출력시 순서는
3 : three, 1: one, 5 : five 처럼 뒤섞일 수 있습니다.
이유는 간단합니다.
Dictionary는 내부적으로 해시값을 기반으로 데이터의 저장 위치를 계산하기 때문에 입력 순서와 출력 순서는 전혀 상관이 없습니다.
해시 테이블 구조와 충돌 처리
Dictionary는 키를 해시값으로 변환한 뒤, 이를 이용해 값을 저장합니다.
이때 해시값이 중복될 수 있는데, 이를 해시 충돌이라고 합니다.
충돌이 발생하면 Dictionary는 내부적으로 체인(Chain) 구조를 만들어 같은 해시칸에 여러 개의 데이터를 연결 리스트처럼 이어붙입니다.
buckets[2] → entries[4] → entries[3] → entries[2] → ...
이 체인은 Next 포인터로 이어지며, Dictionary는 이를 순차적으로 비교해 정확한 값을 찾아냅니다.
중요한 점은, 이 모든 충돌 처리 과정은 자동으로 처리되기 때문에 프로그래머가 직접 신경 쓸 필요가 없다는 것입니다.
정리
• Dictionary[key]는 배열의 인덱스가 아니라, 지정한 키값으로 접근하는 구조입니다.
• for (int i = 0; i < dict.Count; i++) 방식은 키가 연속된 정수형이 아닌 이상 오류가 납니다.
• 순회에는 반드시 foreach를 사용하는 것이 안전하며, 순서도 보장되지 않는다는 점을 기억해야 합니다.
• 내부적으로는 해시 테이블 기반으로, 해시 충돌이 생기면 체인 방식으로 데이터를 이어붙입니다.
• 이러한 구조 덕분에 Dictionary는 매우 빠른 검색 속도를 제공하지만, 배열처럼 다루면 큰 오해가 생깁니다.
이제부터는 Dictionary를 배열처럼 생겼다고 해서 배열처럼 다루지 마세요.
모양은 비슷하지만, 속은 완전히 다르니까요.
'C#' 카테고리의 다른 글
C# 에서 temp 없이 값 교환하는 법, 이렇게 간단해도 될까요? (0) | 2025.05.04 |
---|---|
하드코딩으로 구현한 간단한 퀘스트 분기 처리 (0) | 2025.05.02 |
Parsing과 TryParse() 계열 함수들 (0) | 2025.04.30 |
이벤트 관리를 위한 설계 제안 (0) | 2025.04.30 |
Unity 에서 Singleton 클래스에 Instance로 접근하는 이유 (0) | 2025.04.30 |