Golang 다차원 배열

GolangBeginner
지금 연습하기

소개

이전 섹션에서 배열의 기본 사용법에 대해 배웠습니다.

배열에는 어떤 유형의 요소가 들어갈 수 있을까요?

Go 에서 배열의 요소는 정수, 문자열 또는 사용자 정의 유형과 같은 모든 기본 유형일 수 있습니다.

배열의 요소가 배열인 경우 어떻게 될까요?

그러면 다차원 배열이 됩니다.

Multidimensional Array

위 그림과 같이 보라색 상자가 원래 배열입니다.

보라색 상자 배열의 각 요소는 새로운 배열 (빨간색 상자) 입니다.

핵심 개념:

  • 2 차원 배열의 정의
  • 2 차원 배열의 초기화
  • 2 차원 배열 순회 (Traversing)
  • 다차원 배열의 사용
이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 100%입니다.학습자들로부터 96%의 긍정적인 리뷰율을 받았습니다.

2 차원 배열 정의

일반적인 정의

일반 배열을 정의하는 방법을 기억하시나요?

var variableName [elementCount]variableType

그렇다면 이 가장 기본적인 방법으로 2 차원 배열을 어떻게 정의할까요?

var variableName [elementCount][elementCount]variableType

유일한 차이점은 원래 [elementCount] 앞에 다른 [elementCount]를 추가하여 [elementCount][elementCount] 형식을 형성한다는 것입니다.

예를 들어, int 타입의 10*10 용량을 가진 a라는 2 차원 배열을 정의하려면 다음 구문을 사용할 수 있습니다.

var a [10][10]int

간결한 정의

짧은 변수 선언과 마찬가지로, 간결한 정의 방법을 사용하여 배열, 심지어 다차원 배열도 선언할 수 있습니다.

:=를 사용하여 다차원 배열을 포함한 배열을 선언할 수 있습니다.

예를 들어:

a := [10][10]int{}

이 방법으로 크기가 10*10인 정수 2 차원 배열을 정의합니다.

2 차원 배열 초기화

1 차원 배열과 유사하게, 2 차원 배열을 다음과 같은 방법으로 초기화할 수 있습니다.

  • 초기화 목록 (Initialization list)
  • 길이 추론 초기화 (Inferred length initialization)
  • 지정된 인덱스 값 초기화 (Specified index value initialization)

이러한 방법을 어떻게 사용하는지 기억하시나요?

이전 섹션에서 1 차원 배열에서 이러한 방법을 사용하는 방법을 배웠습니다. 잊어버렸더라도 괜찮습니다.

다음 섹션에서는 이 세 가지 초기화 방법을 검토하고 이를 2 차원 배열로 확장합니다.

초기화 목록을 사용한 2 차원 배열 초기화

이전 섹션에서 생성한 array.go 파일을 계속 사용해 보겠습니다. 작업을 저장하지 않았다면 다음과 같이 파일을 생성할 수 있습니다.

touch ~/project/array.go

array.go에 다음 코드를 작성합니다.

package main

import "fmt"

func main() {
    // 자동으로 0 으로 초기화
    var simpleArray [3][3]int
    // 지정된 초기 값을 사용하여 초기화, 누락된 요소에 대한 기본값 사용
    var numArray = [3][3]int{{1, 2, 3}, {2, 3, 4}}
    // 지정된 초기 값을 사용하여 초기화
    var cityArray = [2][2]string{{"London", "Chengdu"}, {"Paris", "Boston"}}
    fmt.Println(simpleArray) // [[0 0 0] [0 0 0] [0 0 0]]
    fmt.Println(numArray)    // [[1 2 3] [2 3 4] [0 0 0]]
    fmt.Println(cityArray)   // [[London Chengdu] [Paris Boston]]
}

위 코드는 초기화 목록을 사용하여 2 차원 배열을 초기화하는 세 가지 방법을 보여줍니다.

다음 명령을 사용하여 코드를 실행합니다.

go run ~/project/array.go

출력 결과는 다음과 같습니다.

[[0 0 0] [0 0 0] [0 0 0]]
[[1 2 3] [2 3 4] [0 0 0]]
[[London Chengdu] [Paris Boston]]

값을 수정하고 1 차원 배열에 대한 초기화 방법을 검토할 수 있습니다.

추론된 길이를 사용한 2 차원 배열 초기화

2 차원 배열에서 1 차원 배열에서 했던 것처럼 길이 추론 (inferred length) 방법을 사용하여 초기화할 수 있습니다.

array.go에 다음 코드를 작성합니다.

package main

import "fmt"

func main() {
    // 자동으로 0 으로 초기화
    var simpleArray [3][3]int
    // 지정된 초기 값을 사용하여 초기화, 누락된 요소에 대한 기본값 사용
    var numArray = [...][]int{{1, 2, 3, 3}, {2, 3, 4, 3}, {0}}
    // 지정된 초기 값을 사용하여 초기화
    var cityArray = [...][2]string{{"London", "Chengdu"}, {"Paris", "Boston"}}
    fmt.Println(simpleArray) // [[0 0 0] [0 0 0] [0 0 0]]
    fmt.Println(numArray)    // [[1 2 3 3] [2 3 4 3] [0]]
    fmt.Println(cityArray)   // [[London Chengdu] [Paris Boston]]
}

위 코드는 길이 추론을 사용하여 2 차원 배열을 초기화하는 것을 보여줍니다.

go run ~/project/array.go

출력 결과는 초기화 목록 (initialization list) 방법과 동일합니다.

[[0 0 0] [0 0 0] [0 0 0]]
[[1 2 3 3] [2 3 4 3] [0]]
[[London Chengdu] [Paris Boston]]

그러나 1 차원 배열과 달리, 2 차원 배열의 길이 추론 초기화에서 ... 기호는 첫 번째 대괄호 안에만 존재할 수 있습니다.

예를 들어:

var numArray = [...][]int{{1, 2, 3, 3}, {2, 3, 4, 3}}

이 코드는 유효하지만, 다음 두 가지 변형은 잘못되었습니다.

var numArray = [][...]int{{1, 2, 3, 3}, {2, 3, 4, 3}}
var numArray = [...][...]int{{1, 2, 3, 3}, {2, 3, 4, 3}}

또한 numArraycityArray를 비교해 보겠습니다.

cityArray에서 2 차원 배열의 크기의 두 번째 매개변수를 지정하는 것을 볼 수 있습니다. 아래와 같습니다.

var cityArray = [...][2]string{{"London", "Chengdu"}, {"Paris", "Boston"}}

이는 초기화 중에 각 하위 배열의 크기2로 지정한다는 의미입니다.

초기화 중에 주어진 값이 충분하지 않으면, 데이터 유형의 기본값이 누락된 요소를 채우는 데 사용됩니다.

주어진 값의 수가 지정된 크기를 초과하면 오류가 발생합니다.

지정된 인덱스 값을 사용한 2 차원 배열 초기화

1 차원 배열과 유사하게, 2 차원 배열에서도 지정된 인덱스 값 (index value) 을 사용하여 초기화할 수 있습니다. 과정은 유사합니다.

array.go에 다음 코드를 작성합니다.

package main

import "fmt"

func main() {
    a := [...][]int{1: {1, 2, 3}, 3: {4, 7, 9}}
    fmt.Println(a)                  // [[] [1 2 3] [] [4 7 9]]
    fmt.Printf("Type of array a: %T\n", a) // Type of array a: [4][]int
}
go run ~/project/array.go

출력 결과는 다음과 같습니다.

[[] [1 2 3] [] [4 7 9]]
Type of array a: [4][]int

위 코드는 배열 a를 결정되지 않은 길이 (indeterminate length) 를 가진 2 차원 배열로 정의합니다. 인덱스 1에 값 [1 2 3]을 할당하고, 인덱스 3에 값 [4 7 9]를 할당합니다.

자동으로 추론된 길이의 경우, 배열 a의 타입은 [4][]int입니다.

2 차원 배열 순회

2 차원 배열을 어떻게 순회할까요?

1 차원 배열을 배울 때, 배열을 순회하는 두 가지 방법, 즉 range 키워드 사용과 인덱스 번호 (index number) 사용을 배웠습니다.

이제 이 두 가지 방법을 2 차원 배열을 순회하는 데 적용해 보겠습니다.

array.go에 다음 코드를 작성합니다.

package main

import "fmt"

func main() {
    a := [...][]int{{123, 321, 222}, {404, 501, 503}, {857, 419, 857}}
    // Method 1: using the range keyword
    fmt.Println("Traversing the Two-Dimensional Array Using the range Keyword")
    for index, value := range a {
        for i, j := range value {
            fmt.Println(index, i, j)
        }
    }
    // Method 2: using index numbers
    fmt.Println("\nTraversing the Two-Dimensional Array Using Index Numbers")
    for i := 0; i < len(a); i++ {
        for j := 0; j < len(a[i]); j++ {
            fmt.Println(i, j, a[i][j])
        }
    }
}

위 코드는 2 차원 배열을 순회하는 두 가지 방법을 보여줍니다.

go run ~/project/array.go

출력 결과는 다음과 같습니다.

Traversing the Two-Dimensional Array Using the range Keyword
0 0 123
0 1 321
0 2 222
1 0 404
1 1 501
1 2 503
2 0 857
2 1 419
2 2 857

Traversing the Two-Dimensional Array Using Index Numbers
0 0 123
0 1 321
0 2 222
1 0 404
1 1 501
1 2 503
2 0 857
2 1 419
2 2 857

두 방법 모두 동일한 결과를 생성하지만, 근본적으로 다릅니다. 이러한 차이점은 실제로 배열을 사용할 때 특히 명확해질 것입니다.

배열의 실용적인 사용

이전 섹션에서, 배열 순회 (array traversal) 의 두 가지 방법이 근본적으로 다르다고 언급했습니다.

이것을 설명하기 위해 작은 예제를 사용해 보겠습니다.

array.go에 다음 코드를 작성합니다.

package main

import "fmt"

func main() {
    a := [...][]int{{123, 321, 222}, {404, 501, 503}, {857, 419, 857}}
    // Method 1: using the range keyword
    fmt.Println("Traversing the Two-Dimensional Array Using the range Keyword")
    for _, value := range a {
        for _, j := range value {
            fmt.Println(j)
        }
    }
    fmt.Println(a)
    // Method 2: using index numbers
    fmt.Println("\nTraversing the Two-Dimensional Array Using Index Numbers")
    for i := 0; i < len(a); i++ {
        for j := 0; j < len(a[i]); j++ {
            fmt.Println(a[i][j])
            a[i][j] = 0
        }
    }
    fmt.Println(a)
}

위 코드는 두 가지 다른 방법을 사용하여 2 차원 배열의 모든 값을 0으로 설정하는 것을 보여줍니다.

go run ~/project/array.go

프로그램 출력 결과는 다음과 같습니다.

Traversing the Two-Dimensional Array Using the range Keyword
123
321
222
404
501
503
857
419
857
[[123 321 222] [404 501 503] [857 419 857]]

Traversing the Two-Dimensional Array Using Index Numbers
123
321
222
404
501
503
857
419
857
[[0 0 0] [0 0 0] [0 0 0]]

range 키워드를 사용하여 배열을 순회할 때, 값을 수정해도 아무런 효과가 없다는 것을 알 수 있습니다. 그러나 인덱스 번호를 사용하여 배열을 순회한 후에는 값을 수정하는 것이 효과적입니다. 이는 range 키워드를 사용하여 배열을 순회할 때, 루프 변수 j가 실제로 배열 값의 **복사본 (copy)**이기 때문입니다. 복사본의 값을 수정하는 것은 원래 배열 a에 영향을 미치지 않습니다. 그러나 인덱스 번호를 사용하여 배열을 순회할 때는 원래 배열의 값을 수정하는 것이 유효합니다.

2 차원 배열의 업스케일링

때로는 3 차원 배열 또는 4 차원 배열을 사용해야 할 필요가 있습니다.

더 높은 차원의 배열로 확장하는 것은 1 차원 배열을 2 차원 배열로 확장하는 것과 크게 다르지 않습니다.

간단한 예제를 살펴보겠습니다.

package main

import "fmt"

func main() {
    a := [2][2][2]int{}
    for i := 0; i < 2; i++ {
        for j := 0; j < 2; j++ {
            for k := 0; k < 2; k++ {
                a[i][j][k] = 1
            }
        }
    }
    fmt.Println(a)
}

위 코드는 3 차원 배열을 정의하고 사용하는 방법을 보여줍니다. 4 차원 또는 더 높은 차원의 배열도 동일한 과정을 거칩니다.

go run ~/project/array.go

출력 결과는 다음과 같습니다.

[[[1 1] [1 1]] [[1 1] [1 1]]]

하지만, 더 높은 차원의 배열은 일반적으로 사용되지 않습니다. 따라서 개념을 이해하는 것으로 충분합니다.

요약

이 랩 (lab) 에서 우리는 다음을 배웠습니다.

  • 2 차원 배열을 정의하는 두 가지 방법
  • 2 차원 배열을 초기화하는 세 가지 방법
  • 2 차원 배열을 순회하는 두 가지 방법
  • 실제 사용에서 두 가지 순회 방법의 차이점
  • 다차원 배열 사용에 대한 개요