프로그래밍을 하다보면, 어떤 키워드에 해당하는 정보를 빠르게 찾아야 할 때가 많습니다.
예를 들면, 이름으로 전화번호를 찾거나, 아이템 이름으로 가격을 찾는 상황 등이 있습니다.
이럴 때 유용하게 쓰이는 게 바로 Dictionary입니다.
Dictionary 란?
Dictionary는 말 그대로 "사전" 입니다.
Key와 Value를 한 쌍으로 묶어서 데이터를 저장하는 구조입니다.
배열이나 리스트는 숫자 인덱스로 값을 찾지만, Dictionary는 key 로 값 (value) 을 바로 찾을 수 있어서 훨씬 직관적입니다.
우리 생활 속 Dictionary
• 이름으로 전화번호 찾기
예) 김아무개 : 010-1234-5678
• 학번으로 이름 찾기
예) 2025821000 : 김아무개
Dictionary 의 특징
• 키 (Key) 를 이용해 값 (Value) 을 바로 찾는 해시 테이블 기반이므로 시간 복잡도는 O(1) 입니다.
• Key 값은 고유해야 합니다. (중복 불가)
• Value 값은 중복 가능합니다.
• KeyValuePair<TKey, TValue> 구조체를 여러 개 담은 구조가 Dictionary 입니다.
public struct KeyValuePair<TKey, TValue>
{
private readonly TKey key;
private readonly TValue value;
}
원형과 선언
원형은 Dictionary<TKey, TValue> 이며, TKey 는 key 타입, TValue 는 value 타입입니다.
그리고 선언은 다음과 같이 쓸 수 있습니다.
// key : string 형, value : int 형
Dictionary<string, int> scoreTable = new Dictionary<string, int>();
// key : string 형, value : string 형
Dictionary<string, string> questTable = new Dictionary<string, string>();
// key : string 형, value : Item 구조체
struct Item
{
public string name;
public string desc;
public int price;
}
Dictionary<string, Item> itemTable = new Dictionary<string, Item>();
데이터 추가
Add() 함수 사용
이 방식은 key 값이 중복일 경우, 예외를 발생시킵니다.
scoreTable.Add("alice", 85);
scoreTable.Add("bob", 90);
scoreTable.Add("james", 78);
Index ( [ ] ) 사용
이 방식은 key 값이 중복일 경우, 예외를 발생시키지 않고 덮어씁니다.
scoreTable["alice"] = 85;
scoreTable["bob"] = 90;
scoreTable["john"] = 78;
scoreTable["lee"] = 91;
// 예외 없이 덮어씀
scoreTable["john"] = 83;
중괄호를 이용한 초기화
Dictionary<string, string> phoneBook1 = new Dictionary<string, string>()
{
{ "1번 사람", "010 - 1234 - 1234" },
{ "2번 사람", "010 - 1234 - 2345" },
{ "3번 사람", "010 - 1234 - 3456" },
{ "4번 사람", "010 - 1234 - 4567" },
{ "5번 사람", "010 - 1234 - 5678" },
};
또는 () 생략 가능
Dictionary<string, string> phoneBook2 = new Dictionary<string, string>
{
{ "1번 사람", "010 - 1234 - 1234" },
{ "2번 사람", "010 - 1234 - 2345" },
{ "3번 사람", "010 - 1234 - 3456" },
{ "4번 사람", "010 - 1234 - 4567" },
{ "5번 사람", "010 - 1234 - 5678" },
};
값 조회
Index ( [ ] ) 사용
이 방식은 찾고자 하는 key 가 없을 경우, 예외를 발생시킵니다.
// key 가 없으면 예외 발생
int score = scoreTable["alice"];
이 방식을 사용하면, 직접 값을 바꾸는 것이 가능합니다. 다만, 위에서 언급했듯이 예외가 발생할 수 있으므로 간단하지만, 조심스럽게 사용해야 합니다.
scoreTable["alice"] = 95;
scoreTable["alice"]++;
TryGetValue () 를 이용
이 방식은 찾고자 하는 key 가 없을 경우, 예외를 발생시키지 않는 대신 false 를 반환합니다.
if (scoreTable.TryGetValue("alice", out int score))
{
Console.WriteLine(score);
}
else
{
Console.WriteLine("해당 이름이 없습니다.");
}
이 방식을 사용하면, 다음과 같이 값을 변경해서 넣어주어야 하는 불편함은 있습니다.
if (scoreTable.TryGetValue("alice", out int score))
{
score++;
scoreTable["alice"] = score;
}
else
{
Console.WriteLine("해당 이름이 없습니다.");
}
값 삭제
scoreTable.Remove("bob");
실패할 경우의 처리가 필요하다면, 다음과 같이 작성하면 됩니다.
if (scoreTable.Remove("bob"))
Console.WriteLine("삭제 성공");
else
Console.WriteLine("삭제 실패");
전체 비우기
// 모든 항목 삭제
scoreTable.Clear();
foreach 순회
Dictionary 는 내부적으로 Key와 Value를 한 쌍으로 저장하는 KeyValuePair<TKey, TValue> 구조체의 집합입니다.
그래서 foreach() 문으로 Dictionary 를 순회하면, 반복자(IEnumerator) 가 하나씩 꺼내주는 요소의 타입은 KeyValuePair<string, int> 형태가 됩니다. 이 타입은 길고 복잡하기 때문에 보통 var 키워드로 간단히 표현합니다.
foreach (KeyValuePair<string, int> pair in scoreTable)
{
Console.WriteLine("Key: " + pair.Key);
Console.WriteLine("Value: " + pair.Value);
}
또는 간단히
foreach (var pair in scoreTable)
{
Console.WriteLine("Key: " + pair.Key);
Console.WriteLine("Value: " + pair.Value);
}
Dictionary 를 활용한 등록, 조회, 값 수정
foreach() 는 순회 중에 컬렉션의 크기가 변해서는 안됩니다. 즉, foreach() 내부에서 Add(), Remove() 같은 함수를 쓰면 오류가 발생합니다. 그러나 값 자체의 수정은 문제되지 않습니다. 따라서 fruitPrices[key] = value + 100 처럼 인덱서를 이용해 값을 변경하는 코드는 가능하며 위험하지도 않습니다.
// 과일 이름과 가격 등록
Dictionary<string, int> fruitPrices = new Dictionary<string, int>()
{
{ "사과", 1500 },
{ "바나나", 1200 },
{ "오렌지", 1800 },
{ "포도", 2000 }
{ "딸기", 3000 }
};
Console.WriteLine("[가격 인상 전]");
foreach (var pair in fruitPrices)
{
Console.WriteLine($"{pair.Key} : {pair.Value}원");
}
// foreach 순회 중에는 key/value 추가나 삭제는 불가능하지만,
// 인덱서를 이용한 값 수정은 가능합니다.
foreach (var pair in fruitPrices)
{
fruitPrices[pair.Key] = pair.Value + 100;
}
Console.WriteLine("\n[가격 인상 후]");
foreach (var pair in fruitPrices)
{
Console.WriteLine($"{pair.Key} : {pair.Value}원");
}
정리
이처럼 Dictionary는 키(Key) 만 알면 원하는 값을 빠르게 찾을 수 있는 매우 강력한 자료구조입니다.
사용법도 간단하지만, 인덱서 ( [ ] ) 방식과 TryGetValue() 의 차이, Add()와 [ ] 의 동작 차이처럼 기본적인 원리를 잘 이해하고 사용하는 것이 중요합니다.
'C#' 카테고리의 다른 글
컬렉션 (Collection) 의 깊이 있는 이해 (feat. IEnumerable, ICollection) (0) | 2025.07.24 |
---|---|
구조체를 List<T> 에 추가하는 방법들 (0) | 2025.07.19 |
foreach() 가 내부적으로 동작하는 방식 (0) | 2025.07.15 |
Sort() 를 보다 깊이있게 이해하기 (0) | 2025.07.10 |
배열과 리스트를 정렬하는 방법 (0) | 2025.07.10 |