배열

배열 데이터 구조에 형식이 동일한 변수를 여러 개 저장할 수 있습니다. 요소의 형식을 지정하여 배열을 선언합니다. 배열이 모든 형식의 요소를 저장하도록 하려는 경우 object를 해당 형식으로 지정할 수 있습니다. C#의 통합 형식 시스템에서 사용자 정의 및 미리 정의된 참조 형식과 값 형식을 비롯한 모든 형식은 직접 또는 간접적으로 Object에서 상속합니다.

type[] arrayName;

배열에는 다음과 같은 속성이 있습니다.

  • 배열은 단일 차원, 다차원 또는 가변일 수 있습니다.
  • 차원 수는 배열 변수를 선언할 때 설정됩니다. 각 차원의 길이는 배열 인스턴스가 만들어질 때 설정됩니다. 이러한 값은 인스턴스의 수명 동안 변경할 수 없습니다.
  • 가변 배열은 배열의 배열이며 각 멤버 배열의 기본값은 null입니다.
  • 배열은 0으로 인덱싱됩니다. n 요소는 0부터 n-1로 인덱싱됩니다.
  • 배열 요소 형식은 배열 형식을 비롯한 어떤 형식도 될 수 있습니다.
  • 배열 형식은 Array 추상 기본 형식에서 파생된 참조 형식입니다. 모든 배열은 IListIEnumerable을 구현합니다. foreach 문을 사용하여 배열을 반복할 수 있습니다. 단일 차원 배열은 IList<T>IEnumerable<T>도 구현합니다.

배열 요소는 배열이 만들어질 때 알려진 값으로 초기화될 수 있습니다. C# 12부터 모든 컬렉션 형식은 컬렉션 식을 사용하여 초기화할 수 있습니다. 초기화되지 않은 요소는 기본값으로 설정됩니다. 기본값은 0비트 패턴입니다. 모든 참조 형식(null을 허용하지 않는 형식 포함)의 값은 null입니다. 모든 값 형식에는 0비트 패턴이 있습니다. 이는 Nullable<T>.HasValue 속성이 false이고 Nullable<T>.Value 속성이 정의되지 않았음을 의미합니다. .NET 구현에서 Value 속성은 예외를 throw합니다.

다음 예제에서는 단일 차원, 다차원 및 가변 배열을 만듭니다.

// Declare a single-dimensional array of 5 integers.
int[] array1 = new int[5];

// Declare and set array element values.
int[] array2 = [1, 2, 3, 4, 5, 6];

// Declare a two dimensional array.
int[,] multiDimensionalArray1 = new int[2, 3];

// Declare and set array element values.
int[,] multiDimensionalArray2 = { { 1, 2, 3 }, { 4, 5, 6 } };

// Declare a jagged array.
int[][] jaggedArray = new int[6][];

// Set the values of the first array in the jagged array structure.
jaggedArray[0] = [1, 2, 3, 4];

1차원 배열

1차원 배열은 유사한 요소의 시퀀스입니다. 인덱스를 통해 요소에 액세스합니다. 인덱스는 시퀀스의 시퀀스 위치입니다. 배열의 첫 번째 요소는 인덱스 0에 있습니다. 배열 요소 형식과 요소 수를 지정하는 new 연산자를 사용하여 1차원 배열을 만듭니다. 다음 예에서는 1차원 배열을 선언하고 초기화합니다.

int[] array = new int[5];
string[] weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

Console.WriteLine(weekDays[0]);
Console.WriteLine(weekDays[1]);
Console.WriteLine(weekDays[2]);
Console.WriteLine(weekDays[3]);
Console.WriteLine(weekDays[4]);
Console.WriteLine(weekDays[5]);
Console.WriteLine(weekDays[6]);

/*Output:
Sun
Mon
Tue
Wed
Thu
Fri
Sat
*/

첫 번째 선언은 array[0]에서 array[4]까지 5개의 정수로 구성된 초기화되지 않은 배열을 선언합니다. 배열의 요소는 요소 형식의 기본값(정수의 경우 0)으로 초기화됩니다. 두 번째 선언은 문자열 배열을 선언하고 해당 배열의 7개 값을 모두 초기화합니다. 일련의 Console.WriteLine 문은 weekDay 배열의 모든 요소를 인쇄합니다. 1차원 배열의 경우 foreach 문은 인덱스 0으로 시작하고 인덱스 Length - 1로 끝나는 늘어나는 인덱스 순서로 요소를 처리합니다.

1차원 배열을 인수로 전달

초기화된 1차원 배열을 메서드에 전달할 수 있습니다. 다음 예제에서는 문자열 배열이 초기화되고 문자열에 대한 DisplayArray 메서드에 인수로 전달됩니다. 메서드가 배열 요소를 표시합니다. 다음으로 ChangeArray 메서드는 배열 요소를 반대로 전환한 다음, ChangeArrayElements 메서드는 배열의 처음 세 요소를 수정합니다. 각 메서드가 반환된 후 DisplayArray 메서드는 배열을 값으로 전달해도 배열 요소가 변경되지 않는다는 것을 보여줍니다.

class ArrayExample
{
    static void DisplayArray(string[] arr) => Console.WriteLine(string.Join(" ", arr));

    // Change the array by reversing its elements.
    static void ChangeArray(string[] arr) => Array.Reverse(arr);

    static void ChangeArrayElements(string[] arr)
    {
        // Change the value of the first three array elements.
        arr[0] = "Mon";
        arr[1] = "Wed";
        arr[2] = "Fri";
    }

    static void Main()
    {
        // Declare and initialize an array.
        string[] weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
        // Display the array elements.
        DisplayArray(weekDays);
        Console.WriteLine();

        // Reverse the array.
        ChangeArray(weekDays);
        // Display the array again to verify that it stays reversed.
        Console.WriteLine("Array weekDays after the call to ChangeArray:");
        DisplayArray(weekDays);
        Console.WriteLine();

        // Assign new values to individual array elements.
        ChangeArrayElements(weekDays);
        // Display the array again to verify that it has changed.
        Console.WriteLine("Array weekDays after the call to ChangeArrayElements:");
        DisplayArray(weekDays);
    }
}
// The example displays the following output:
//         Sun Mon Tue Wed Thu Fri Sat
//
//        Array weekDays after the call to ChangeArray:
//        Sat Fri Thu Wed Tue Mon Sun
//
//        Array weekDays after the call to ChangeArrayElements:
//        Mon Wed Fri Wed Tue Mon Sun

다차원 배열

배열에 둘 이상의 차원이 있을 수 있습니다. 예를 들어, 다음 선언은 4개의 배열을 만듭니다. 두 개는 2차원이고, 두 개는 3차원입니다. 처음 두 선언은 각 차원의 길이를 선언하지만 배열 값을 초기화하지 않습니다. 두 번째 두 선언에서는 이니셜라이저를 사용하여 다차원 배열의 각 요소 값을 설정합니다.

int[,] array2DDeclaration = new int[4, 2];

int[,,] array3DDeclaration = new int[4, 2, 3];

// Two-dimensional array.
int[,] array2DInitialization =  { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// Three-dimensional array.
int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4,   5,  6 } },
                                { { 7, 8, 9 }, { 10, 11, 12 } } };

// Accessing array elements.
System.Console.WriteLine(array2DInitialization[0, 0]);
System.Console.WriteLine(array2DInitialization[0, 1]);
System.Console.WriteLine(array2DInitialization[1, 0]);
System.Console.WriteLine(array2DInitialization[1, 1]);

System.Console.WriteLine(array2DInitialization[3, 0]);
System.Console.WriteLine(array2DInitialization[3, 1]);
// Output:
// 1
// 2
// 3
// 4
// 7
// 8

System.Console.WriteLine(array3D[1, 0, 1]);
System.Console.WriteLine(array3D[1, 1, 2]);
// Output:
// 8
// 12

// Getting the total count of elements or the length of a given dimension.
var allLength = array3D.Length;
var total = 1;
for (int i = 0; i < array3D.Rank; i++)
{
    total *= array3D.GetLength(i);
}
System.Console.WriteLine($"{allLength} equals {total}");
// Output:
// 12 equals 12

다차원 배열의 경우 요소는 가장 오른쪽 차원의 인덱스가 먼저 증가되고 다음 왼쪽 차원이 증가하는 방식으로 가장 왼쪽 인덱스까지 트래버스됩니다. 다음 예에서는 2D 배열과 3D 배열을 모두 열거합니다.

int[,] numbers2D = { { 9, 99 }, { 3, 33 }, { 5, 55 } };

foreach (int i in numbers2D)
{
    System.Console.Write($"{i} ");
}
// Output: 9 99 3 33 5 55

int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4,   5,  6 } },
                        { { 7, 8, 9 }, { 10, 11, 12 } } };
foreach (int i in array3D)
{
    System.Console.Write($"{i} ");
}
// Output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

2D 배열에서는 왼쪽 인덱스를 으로, 오른쪽 인덱스를 로 생각할 수 있습니다.

그러나 다차원 배열에서 중첩 for 루프를 사용하면 배열 요소를 처리하는 순서를 더 강력하게 제어할 수 있습니다.

int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4,   5,  6 } },
                        { { 7, 8, 9 }, { 10, 11, 12 } } };

for (int i = 0; i < array3D.GetLength(0); i++)
{
    for (int j = 0; j < array3D.GetLength(1); j++)
    {
        for (int k = 0; k < array3D.GetLength(2); k++)
        {
            System.Console.Write($"{array3D[i, j, k]} ");
        }
        System.Console.WriteLine();
    }
    System.Console.WriteLine();
}
// Output (including blank lines): 
// 1 2 3
// 4 5 6
// 
// 7 8 9
// 10 11 12
//

다차원 배열을 인수로 전달

초기화된 다차원 배열을 1차원 배열 전달과 동일한 방식으로 메서드에 전달합니다. 다음 코드는 2차원 배열을 해당 인수로 허용하는 인쇄 메서드의 부분 선언을 보여 줍니다. 다음 예제와 같이 한 단계로 새 배열을 초기화하고 전달할 수 있습니다. 다음 예제에서는 정수의 2차원 배열이 초기화되고 Print2DArray 메서드에 전달됩니다. 메서드가 배열 요소를 표시합니다.

static void Print2DArray(int[,] arr)
{
    // Display the array elements.
    for (int i = 0; i < arr.GetLength(0); i++)
    {
        for (int j = 0; j < arr.GetLength(1); j++)
        {
            System.Console.WriteLine("Element({0},{1})={2}", i, j, arr[i, j]);
        }
    }
}
static void ExampleUsage()
{
    // Pass the array as an argument.
    Print2DArray(new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } });
}
/* Output:
    Element(0,0)=1
    Element(0,1)=2
    Element(1,0)=3
    Element(1,1)=4
    Element(2,0)=5
    Element(2,1)=6
    Element(3,0)=7
    Element(3,1)=8
*/

가변 배열

가변 배열은 요소, 아마도 요소의 크기가 서로 다른 배열입니다. 가변 배열을 “배열의 배열”이라고도 합니다. 해당 요소는 참조 형식이며 null로 초기화됩니다. 다음 예제에서는 가변 배열을 선언, 초기화 및 액세스하는 방법을 보여 줍니다. 첫 번째 예인 jaggedArray는 하나의 문으로 선언됩니다. 포함된 각 배열은 후속 문에서 만들어집니다. 두 번째 예인 jaggedArray2는 하나의 문에서 선언되고 초기화됩니다. 가변 배열과 다차원 배열을 함께 사용할 수 있습니다. 마지막 예인 jaggedArray3은 크기가 서로 다른 세 개의 2차원 배열 요소를 포함하는 1차원 가변 배열의 선언 및 초기화입니다.

int[][] jaggedArray = new int[3][];

jaggedArray[0] = [1, 3, 5, 7, 9];
jaggedArray[1] = [0, 2, 4, 6];
jaggedArray[2] = [11, 22];

int[][] jaggedArray2 = 
[
    [1, 3, 5, 7, 9],
    [0, 2, 4, 6],
    [11, 22]
];

// Assign 77 to the second element ([1]) of the first array ([0]):
jaggedArray2[0][1] = 77;

// Assign 88 to the second element ([1]) of the third array ([2]):
jaggedArray2[2][1] = 88;

int[][,] jaggedArray3 =
[
    new int[,] { {1,3}, {5,7} },
    new int[,] { {0,2}, {4,6}, {8,10} },
    new int[,] { {11,22}, {99,88}, {0,9} }
];

Console.Write("{0}", jaggedArray3[0][1, 0]);
Console.WriteLine(jaggedArray3.Length);

가변 배열의 요소를 사용하려면 먼저 초기화해야 합니다. 각 요소는 그 자체로 배열입니다. 이니셜라이저를 사용하여 배열 요소를 값으로 채우는 것도 가능합니다. 이니셜라이저를 사용하면 배열 크기가 필요하지 않습니다.

이 예제에서는 요소 자체가 배열인 배열을 작성합니다. 각 배열 요소의 크기가 서로 다릅니다.

// Declare the array of two elements.
int[][] arr = new int[2][];

// Initialize the elements.
arr[0] = [1, 3, 5, 7, 9];
arr[1] = [2, 4, 6, 8];

// Display the array elements.
for (int i = 0; i < arr.Length; i++)
{
    System.Console.Write("Element({0}): ", i);

    for (int j = 0; j < arr[i].Length; j++)
    {
        System.Console.Write("{0}{1}", arr[i][j], j == (arr[i].Length - 1) ? "" : " ");
    }
    System.Console.WriteLine();
}
/* Output:
    Element(0): 1 3 5 7 9
    Element(1): 2 4 6 8
*/

암시적으로 형식화된 배열

배열 인스턴스의 형식이 배열 이니셜라이저에 지정된 요소에서 유추되는 암시적으로 형식화된 배열을 만들 수 있습니다. 암시적으로 형식화된 변수에 대한 규칙은 암시적으로 형식화된 배열에도 적용됩니다. 자세한 내용은 암시적으로 형식화된 지역 변수를 참조하세요.

다음 예에서는 암시적으로 형식화된 배열을 만드는 방법을 보여 줍니다.

int[] a = new[] { 1, 10, 100, 1000 }; // int[]

// Accessing array
Console.WriteLine("First element: " + a[0]);
Console.WriteLine("Second element: " + a[1]);
Console.WriteLine("Third element: " + a[2]);
Console.WriteLine("Fourth element: " + a[3]);
/* Outputs
First element: 1
Second element: 10
Third element: 100
Fourth element: 1000
*/

var b = new[] { "hello", null, "world" }; // string[]

// Accessing elements of an array using 'string.Join' method
Console.WriteLine(string.Join(" ", b));
/* Output
hello  world
*/

// single-dimension jagged array
int[][] c =
[
    [1,2,3,4],
    [5,6,7,8]
];
// Looping through the outer array
for (int k = 0; k < c.Length; k++)
{
    // Looping through each inner array
    for (int j = 0; j < c[k].Length; j++)
    {
        // Accessing each element and printing it to the console
        Console.WriteLine($"Element at c[{k}][{j}] is: {c[k][j]}");
    }
}
/* Outputs
Element at c[0][0] is: 1
Element at c[0][1] is: 2
Element at c[0][2] is: 3
Element at c[0][3] is: 4
Element at c[1][0] is: 5
Element at c[1][1] is: 6
Element at c[1][2] is: 7
Element at c[1][3] is: 8
*/

// jagged array of strings
string[][] d =
[
    ["Luca", "Mads", "Luke", "Dinesh"],
    ["Karen", "Suma", "Frances"]
];

// Looping through the outer array
int i = 0;
foreach (var subArray in d)
{
    // Looping through each inner array
    int j = 0;
    foreach (var element in subArray)
    {
        // Accessing each element and printing it to the console
        Console.WriteLine($"Element at d[{i}][{j}] is: {element}");
        j++;
    }
    i++;
}
/* Outputs
Element at d[0][0] is: Luca
Element at d[0][1] is: Mads
Element at d[0][2] is: Luke
Element at d[0][3] is: Dinesh
Element at d[1][0] is: Karen
Element at d[1][1] is: Suma
Element at d[1][2] is: Frances
*/

앞의 예에서 암시적으로 형식화된 배열의 경우 초기화 문의 왼쪽에 대괄호가 사용되지 않는 것을 확인합니다. 또한 가변 배열은 1차원 배열과 마찬가지로 new []를 사용하여 초기화됩니다.

배열이 포함된 무명 형식을 만드는 경우 해당 형식의 개체 이니셜라이저에서 배열을 암시적으로 형식화해야 합니다. 다음 예에서 contacts는 각각 PhoneNumbers라는 배열이 포함된 무명 형식의 암시적으로 형식화된 배열입니다. var 키워드는 개체 이니셜라이저 내에서 사용되지 않습니다.

var contacts = new[]
{
    new
    {
        Name = "Eugene Zabokritski",
        PhoneNumbers = new[] { "206-555-0108", "425-555-0001" }
    },
    new
    {
        Name = "Hanying Feng",
        PhoneNumbers = new[] { "650-555-0199" }
    }
};