서론
C# 프로그래밍에서 데이터를 효율적으로 관리하고 조작하는 능력은 필수적입니다. 이번 포스트에서는 '이것이 C#이다'의 10장 전반부를 다루며, C#의 강력한 데이터 구조인 배열과 컬렉션, 그리고 이를 더욱 유연하게 만드는 인덱서에 대해 알아보겠습니다. 이들은 대규모 데이터 처리부터 복잡한 알고리즘 구현까지 다양한 상황에서 핵심적인 역할을 합니다.
본론
1. System.Index와 ^연산자
C# 8.0부터 도입된 System.Index 형식과 ^ 연산자는 배열과 컬렉션을 다루는 방식에 혁신을 가져왔습니다. 특히 ^ 연산자는 컬렉션의 끝에서부터 요소에 접근할 수 있게 해줍니다.
int[] numbers = { 1, 2, 3, 4, 5 };
Console.WriteLine(numbers[^1]); // 출력: 5 (마지막 요소)
Console.WriteLine(numbers[^2]); // 출력: 4 (뒤에서 두 번째 요소)
C#
복사
이 기능은 Python의 음수 인덱싱과 유사하지만, C#에서는 더 명시적이고 안전합니다. 배열의 길이를 모르더라도 마지막 요소에 쉽게 접근할 수 있어, 코드의 가독성과 유지보수성이 향상됩니다.
2. 배열 초기화의 세 가지 방법
C#에서 배열을 초기화하는 방법은 크게 세 가지가 있습니다. 각 방법은 상황에 따라 유용하게 사용될 수 있습니다.
// 방법 1: 배열의 크기와 요소를 동시에 지정
int[] numbers1 = new int[3] { 1, 2, 3 };
// 방법 2: 배열의 크기만 지정
int[] numbers2 = new int[3];
numbers2[0] = 1; numbers2[1] = 2; numbers2[2] = 3;
// 방법 3: var 키워드와 함께 간단히 초기화
var numbers3 = new[] { 1, 2, 3 };
C#
복사
개인적으로, 첫 번째 방법을 가장 자주 사용합니다. 코드가 조금 길어지지만, 명시적으로 표현해주는 편이 코드의 가독성이나 의도를 드러내는데 좋다고 생각하기 때문입니다. 다만 이는 선택의 문제라고 생각합니다.
3. System.Array
System.Array 클래스는 .NET의 Common Type System (CTS)에서 모든 배열의 기본 클래스입니다. 이 클래스는 배열을 다루는 데 유용한 다양한 메서드와 속성을 제공합니다.
주요 메서드와 속성:
•
Sort(): 배열을 정렬합니다.
•
BinarySearch<T>(): 정렬된 배열에서 요소를 빠르게 찾습니다.
•
IndexOf(): 특정 요소의 인덱스를 찾습니다.
•
Resize<T>(): 배열의 크기를 조정합니다.
•
Length: 배열의 총 요소 수를 반환합니다.
예를 들어, 정렬과 이진 검색을 구현해 봅시다:
int[] numbers = { 3, 1, 4, 1, 5, 9, 2, 6 };
Array.Sort(numbers);
Console.WriteLine(string.Join(", ", numbers)); // 출력: 1, 1, 2, 3, 4, 5, 6, 9
int index = Array.BinarySearch(numbers, 5);
Console.WriteLine($"숫자 5의 인덱스: {index}"); // 출력: 숫자 5의 인덱스: 5
C#
복사
이러한 메서드들은 직접 구현하기 복잡한 알고리즘을 쉽게 사용할 수 있게 해줍니다. 특히 대규모 데이터를 다룰 때 성능 최적화에 큰 도움이 됩니다.
4. 배열 분할하기: System.Range의 활용
C# 8.0에서 도입된 System.Range는 배열이나 문자열의 일부분을 쉽게 추출할 수 있게 해줍니다. .. 연산자를 사용하여 범위를 지정합니다.
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] slice1 = numbers[2..5]; // {2, 3, 4}
int[] slice2 = numbers[..3]; // {0, 1, 2}
int[] slice3 = numbers[7..]; // {7, 8, 9}
C#
복사
이 기능은 데이터 처리나 알고리즘 구현 시 코드를 더 간결하고 읽기 쉽게 만들어 줍니다. 예를 들어, 로그 파일의 특정 시간대 데이터만 추출하거나, 긴 문자열에서 특정 부분만 처리해야 할 때 효과적으로 사용할 수 있습니다.
5. 다차원 배열과 가변 배열
C#은 다차원 배열과 가변 배열(jagged array)을 모두 지원합니다. 이 두 가지 타입의 배열은 각각 다른 상황에서 유용하게 사용될 수 있습니다.
// 2차원 배열
int[,] matrix = new int[3, 3] {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
// 가변 배열
int[][] jaggedArray = new int[3][];
jaggedArray[0] = new int[] { 1, 2, 3 };
jaggedArray[1] = new int[] { 4, 5 };
jaggedArray[2] = new int[] { 6, 7, 8, 9 };
Console.WriteLine($"Matrix[1,1]: {matrix[1, 1]}");// 출력: Matrix[1,1]: 5
Console.WriteLine($"JaggedArray[2][1]: {jaggedArray[2][1]}");// 출력: JaggedArray[2][1]: 7
C#
복사
다차원 배열은 정형화된 데이터(예: 이미지 처리, 행렬 연산)에 적합하며, 가변 배열은 각 행의 길이가 다를 수 있는 데이터(예: 불규칙한 형태의 게임 맵)를 표현하는 데 유용합니다.
결론
이번 포스트에서는 C#의 배열과 관련된 주요 개념들을 살펴보았습니다. 이러한 기능들은 단순히 데이터를 저장하는 것을 넘어, 효율적인 알고리즘 구현과 메모리 관리의 기초가 됩니다.
개인적으로 System.Index와 System.Range의 도입이 가장 인상 깊었습니다. 이 기능들이 코드의 가독성과 유지보수성을 크게 향상시킬 수 있다고 생각합니다. 앞으로 실제 프로젝트에서 이러한 기능들을 적극적으로 활용해 볼 계획입니다.
다음 포스트에서는 컬렉션과 인덱서에 대해 더 자세히 다루겠습니다. 특히 ArrayList, Queue, Stack, Hashtable 등의 컬렉션 타입과 그 사용법, 그리고 커스텀 객체에 배열과 유사한 인덱싱 기능을 추가하는 방법에 대해 알아볼 예정입니다.
참고 자료
•
박상현, "이것이 C#이다", 한빛미디어, 2023