딕셔너리(dictionary)란?
딕셔너리(dictionary)는 키(Key)와 값(Value)을 쌍으로 저장하는 자료구조입니다. 키를 통해 값을 빠르게 찾을 수 있습니다.
기본 개념
- 키-값 쌍: 각 값은 고유한 키로 접근
- 빠른 검색: 키를 통해 O(1) 시간에 값 찾기
- 순서 보장: C# Dictionary는 삽입 순서 유지
딕셔너리(dictionary) 선언
using System.Collections.Generic;
// 방법 1: 빈 딕셔너리 생성
Dictionary<string, int> myDict = new Dictionary<string, int>();
// 방법 2: 초기값과 함께 생성
Dictionary<string, string> playerNames = new Dictionary<string, string>()
{
{ "player1", "홍길동" },
{ "player2", "김철수" }
};
// 방법 3: var 키워드 사용
var scores = new Dictionary<string, int>();
딕셔너리(dictionary) 주요 메서드(method)
Add() - 값 추가
Dictionary<string, int> scores = new Dictionary<string, int>();
scores.Add("player1", 100);
scores.Add("player2", 200);
scores.Add("player3", 150);
접근 및 수정
// 값 접근
int player1Score = scores["player1"]; // 100
// 값 수정
scores["player1"] = 250;
// 값 추가 (Add 대신 인덱서 사용 가능)
scores["player4"] = 300;
ContainsKey() - 키 존재 확인
if (scores.ContainsKey("player1"))
{
Debug.Log("player1이 존재합니다");
int score = scores["player1"];
}
Remove() - 값 제거
scores.Remove("player1");
TryGetValue() - 안전하게 값 가져오기
if (scores.TryGetValue("player1", out int score))
{
Debug.Log($"player1의 점수: {score}");
}
else
{
Debug.Log("player1을 찾을 수 없습니다");
}
Count - 항목 개수
int itemCount = scores.Count;
Debug.Log($"딕셔너리에 {itemCount}개의 항목이 있습니다");
Clear() - 모든 항목 제거
scores.Clear();
딕셔너리(dictionary) 사용 예시
using System.Collections.Generic;
using UnityEngine;
public class DictionaryExample : MonoBehaviour
{
void Start()
{
// 플레이어 점수 딕셔너리
Dictionary<string, int> playerScores = new Dictionary<string, int>();
// 값 추가
playerScores.Add("홍길동", 100);
playerScores.Add("김철수", 200);
playerScores.Add("이영희", 150);
// 값 접근
Debug.Log($"홍길동의 점수: {playerScores["홍길동"]}");
// 값 수정
playerScores["홍길동"] = 250;
// 모든 항목 순회
foreach (KeyValuePair<string, int> pair in playerScores)
{
Debug.Log($"{pair.Key}: {pair.Value}");
}
// 키만 순회
foreach (string key in playerScores.Keys)
{
Debug.Log($"플레이어: {key}");
}
// 값만 순회
foreach (int value in playerScores.Values)
{
Debug.Log($"점수: {value}");
}
}
}
딕셔너리(dictionary) vs 리스트(list) vs 배열(array)
| 특징 | 배열(array) | 리스트(list) | 딕셔너리(dictionary) |
|---|---|---|---|
| 인덱스 | 숫자 (0부터) | 숫자 (0부터) | 키 (임의 타입(type)) |
| 검색 속도 | O(1) | O(n) | O(1) |
| 순서 | 보장 | 보장 | 보장 (C#) |
| 중복 | 가능 | 가능 | 키는 불가, 값은 가능 |
| 크기 | 고정 | 동적 | 동적 |
실전 활용 예시
예시 1: 아이템 관리
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
Dictionary<string, int> inventory = new Dictionary<string, int>();
void Start()
{
AddItem("검", 1);
AddItem("방패", 1);
AddItem("물약", 5);
}
void AddItem(string itemName, int quantity)
{
if (inventory.ContainsKey(itemName))
{
inventory[itemName] += quantity;
}
else
{
inventory.Add(itemName, quantity);
}
Debug.Log($"{itemName} {quantity}개 추가. 총 {inventory[itemName]}개");
}
void UseItem(string itemName, int quantity)
{
if (inventory.ContainsKey(itemName) && inventory[itemName] >= quantity)
{
inventory[itemName] -= quantity;
if (inventory[itemName] == 0)
{
inventory.Remove(itemName);
}
Debug.Log($"{itemName} {quantity}개 사용. 남은 개수: {inventory[itemName]}");
}
else
{
Debug.Log($"{itemName}이(가) 부족합니다");
}
}
void ShowInventory()
{
foreach (var item in inventory)
{
Debug.Log($"{item.Key}: {item.Value}개");
}
}
}
예시 2: 플레이어 정보 관리
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager : MonoBehaviour
{
Dictionary<int, PlayerInfo> players = new Dictionary<int, PlayerInfo>();
public class PlayerInfo
{
public string name;
public int level;
public int hp;
public int maxHp;
}
void Start()
{
// 플레이어 추가
AddPlayer(1, "홍길동", 10, 100);
AddPlayer(2, "김철수", 15, 150);
AddPlayer(3, "이영희", 8, 80);
// 플레이어 정보 조회
if (players.TryGetValue(1, out PlayerInfo player))
{
Debug.Log($"{player.name}의 레벨: {player.level}, HP: {player.hp}/{player.maxHp}");
}
// 플레이어 데미지 처리
TakeDamage(1, 30);
}
void AddPlayer(int id, string name, int level, int maxHp)
{
players[id] = new PlayerInfo
{
name = name,
level = level,
hp = maxHp,
maxHp = maxHp
};
}
void TakeDamage(int playerId, int damage)
{
if (players.TryGetValue(playerId, out PlayerInfo player))
{
player.hp -= damage;
if (player.hp < 0) player.hp = 0;
Debug.Log($"{player.name}이(가) {damage}의 데미지를 받았습니다. HP: {player.hp}/{player.maxHp}");
}
}
}
예시 3: 리소스 관리
using System.Collections.Generic;
using UnityEngine;
public class ResourceManager : MonoBehaviour
{
Dictionary<string, GameObject> prefabCache = new Dictionary<string, GameObject>();
GameObject LoadPrefab(string prefabName)
{
// 캐시에 있으면 반환
if (prefabCache.TryGetValue(prefabName, out GameObject cachedPrefab))
{
return cachedPrefab;
}
// 없으면 로드하고 캐시에 저장
GameObject prefab = Resources.Load<GameObject>(prefabName);
if (prefab != null)
{
prefabCache[prefabName] = prefab;
}
return prefab;
}
void ClearCache()
{
prefabCache.Clear();
}
}
주의사항
- 키 중복: 같은 키를 두 번 추가하면
ArgumentException발생 - 존재하지 않는 키: 없는 키로 접근하면
KeyNotFoundException발생 (TryGetValue 사용 권장) - null 키: Dictionary는 null 키를 허용하지 않음
- 성능: 키 타입(type)에 따라 해시 계산 비용이 다름 (string은 상대적으로 느림)
실전 활용 팁
팁 1: 안전하게 값 가져오기
// ❌ 나쁜 예시
int score = scores["player1"]; // 키가 없으면 에러!
// ✅ 좋은 예시
if (scores.TryGetValue("player1", out int score))
{
Debug.Log(score);
}
else
{
Debug.Log("플레이어를 찾을 수 없습니다");
}
팁 2: 값이 없으면 추가, 있으면 수정
// 방법 1: ContainsKey 사용
if (dict.ContainsKey("key"))
{
dict["key"] = newValue;
}
else
{
dict.Add("key", newValue);
}
// 방법 2: 인덱서 사용 (더 간단)
dict["key"] = newValue; // 키가 없으면 자동으로 추가됨
팁 3: 딕셔너리(dictionary) 초기화 확인
// 딕셔너리가 비어있는지 확인
if (myDict.Count == 0)
{
Debug.Log("딕셔너리가 비어있습니다");
}
// 또는
if (myDict == null || myDict.Count == 0)
{
// 초기화 로직
}
팁 4: LINQ(LINQ)와 함께 사용
using System.Linq;
// 값으로 정렬
var sortedByValue = scores.OrderBy(x => x.Value);
// 키로 필터링
var filtered = scores.Where(x => x.Key.StartsWith("player"));
// 최대값 찾기
var maxScore = scores.Values.Max();