같은 타입의 데이터를 연속적으로 저장할 수 있는 자료구조
// 인벤토리에 들어있는 아이템 ID 초기화
int[] inventory = {101, 103, 105};
foreach(var item in inventory)
{
// 인벤토리에 존재하는 모든 아이템 ID 출력
Console.WriteLine($"보유한 아이템ID: {item}");
}
// 2D 맵 정보(0: 벽, 1: 길)
int[,] mapGrid = {
{1, 1, 1},
{0, 1, 0},
{0, 1, 1}
};
// 2차원 배열 순회 (이동 가능 불가능 판정)
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
if(mapGrid[i, j] == 1)
Console.WriteLine($"({i},{j}) 이동가능");
else
Console.WriteLine($"({i},{j}) 이동 불가능";
}
}
| 컬렉션 | 설명 | 특징 |
|---|---|---|
List<T> | 배열처럼 순서대로 저장하는 리스트 | 크기가 자동 조절됨 |
Dictionary<TKey, TValue> | 키-값 쌍으로 저장 | 키를 통해 빠르게 접근 |
Queue<T> | 선입선출(FIFO) 구조 | 먼저 들어간 게 먼저 나옴 |
Stack<T> | 후입선출(LIFO) 구조 | 나중에 들어간 게 먼저 나옴 |
HashSet<T> | 중복 없이 저장 | 순서 없음, 빠른 검색 |
List<string> items = new List<string>(); // 새로운 리스트 객체 생성
items.Add("검"); // 검 추가
items.Add("포션"); // 포션 추가
items.Remove("검"); // 검 제거
Console.WriteLine(items[0]);
>>> 포션
Dictionary<string, int> itemPrices = new Dictionary<string, int>(); // 새로운 딕셔너리 객체 생성
itemPrices.Add("철 검", 500); // 데이터 추가
itemPrices.Add("나무 방패", 100);
itemPrices.Add("가죽 장화", 300);
itemPrices.Remove("철 검"); // 해당 데이터 삭제
foreach(var key in itemPrices.Keys)
{
Console.WriteLine($"아이템 이름: {key}, 가격: {itemPrices[key]}");
}
>>> 아이템 이름: 나무 방패, 가격: 100
>>> 아이템 이름: 가죽 장화, 가격: 300
Queue<string> questQueue = new Queue<string>(); // 새로운 Queue 객체 생성
// 큐에 데이터 추가
questQueue.Enqueue("던전 탐험");
questQueue.Enqueue("보스 처치");
// 데이터 가져오기 (가장 먼저 추가 된 데이터)
Console.WriteLine(questQueue.Dequeue());
>>> 던전 탐험
Stack<string> menuHistory = new Stack<string>(); // 새로운 Stack 객체 생성
// 스택에 데이터 추가
menuHistory.Push("메인 메뉴");
menuHistory.Push("소리 설정");
// 마지막에 추가된 데이터 가져오기
Console.WriteLine(menuHistory.Pop());
>>> 소리 설정
HashSet<string> uniqueItems = new HashSet<string>(); // 새로운 HashSet 객체 생성
// HashSet에 데이터 추가
uniqueItems.Add("전설의 검");
uniqueItems.Add("전설의 검");
// HashSet 순회하며 데이터 출력
foreach(string item in uniqueItems)
{
Console.WriteLine(item);
}
>>> 전설의 검
| 구분 | 배열 (Array) | 리스트 (List<T>) |
|---|---|---|
| 선언 방식 | int[] arr = new int[3]; | List<int> list = new List<int>(); |
| 크기 | 고정 크기 – 생성 시 크기 결정 | 가변 크기 – 요소 추가/삭제 가능 |
| 성능 | 고정된 구조로 상대적으로 빠름 | 동적으로 크기를 조절하므로 약간 느릴 수 있음 |
| 유연성 | 제한적 (크기 변경 불가) | 유연함 (추가, 삭제 등 다양한 기능 제공) |
| 메서드 지원 | 거의 없음 (단순한 구조) | Add(), Remove(), Contains() 등 다양함 |
| 인덱스 접근 | 지원 (arr[0]) | 지원 (list[0]) |
| 사용 목적 | 크기가 변하지 않는 고정 데이터에 적합 | 크기가 유동적인 데이터에 적합 |
- 리스트는 동적으로 크기를 조정할 수 있어 배열보다 많은 메모리 사용 (데이터의 양이 많으면 성능 저하를 유발할 수 있다)
- 리스트는 연결 리스트로 구현되어서, 인덱스를 이용한 데이터 접근이 배열보다 느리다. (특정 데이터를 찾기 위해선 모든 데이터 순회)
- 데이터 추가, 삭제 등의 작업이 배열보다 간편하지만 코드 복잡도를 증가시킬 수 있다.
-> 따라서, 리스트를 무분별하게 사용하는 것은 좋지 않다. 데이터의 크기와 사용 목적을 고려하여 적절한 것을 선택
public class BaseBallGame
{
public void StartGame()
{
int[] computerNum = GetRandomNumber(); // 랜덤한 숫자배열 가져오기
int attempts = 0;
while (true)
{
// 시도 횟수 증가
attempts++;
// 3자리 숫자 입력 받기
Console.Write("\n세 자리 숫자를 입력하세요(Ex: 123): ");
string input = Console.ReadLine();
// 잘못된 입력 검증
if (input.Length != 3 || !int.TryParse(input, out _))
{
Console.WriteLine("잘못된 입력입니다. 다시 입력하세요.");
continue;
}
// 플레이어의 숫자 int 타입 배열에 저장
int[] playerNum = new int[3];
for (int i = 0; i < 3; i++)
playerNum[i] = int.Parse(input[i].ToString());
// 스트라이크, 볼 초기화
int strike = 0, ball = 0;
// 숫자 판별
for (int i = 0; i < 3; i++)
{
if (playerNum[i] == computerNum[i]) // 같으면 스트라이크
strike++;
else if (computerNum.Contains(playerNum[i])) // 자리는 다르지만 포함하고 있다면 볼
ball++;
}
// 3스트라이크면 종료
if (strike == 3)
{
Console.WriteLine($"정답입니다!!!\n시도 횟수: {attempts}");
break;
}
else
Console.WriteLine($"{strike}스트라이크, {ball}볼");
}
}
private int[] GetRandomNumber()
{
// 랜덤 객체 & numbers 리스트 생성
Random rand = new Random();
List<int> numbers = new List<int>();
// numbers의 길이가 3이 되면 반복 종료
while (numbers.Count < 3)
{
int num = rand.Next(1, 10); // 1 ~ 9 사이 숫자
// 중복을 방지하여 숫자 추가
if (!numbers.Contains(num))
numbers.Add(num);
}
// 배열로 변환 후 반환
return numbers.ToArray();
}
}