Go Language Multidimensional Arrays

Go Arrays

A multidimensional array is an array of arrays. Think of it as aData tableorMatrix, where each element can be accessed via multiple indices.

Multidimensional arrays in Go can be used to handle structured information such as tabular data, matrix operations, or game boards.

Basic concepts

  • One-dimensional array: like points on a straight line, only one coordinate (index) is needed to find a specific element
  • Two-dimensional array: like a table, requiring two coordinates: row and column
  • Three-dimensional array: like a cube, requiring three coordinates: length, width, and height
  • Higher dimensions: theoretically can have many dimensions, but in practice two-dimensional and three-dimensional arrays are most commonly used

This can be compared to our everyday parking spaces:

  • One-dimensional array= a row of parking spaces (only need the parking space number)
  • Two-dimensional array= a multi-story parking lot (need the floor and parking space number)
  • Three-dimensional array= multiple multi-story parking lots (need the parking lot number, floor, and parking space number)

Go supports multidimensional arrays. The following are common ways to declare multidimensional arrays:

var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type

Declaration and initialization:

// Declare a two-dimensional array var arrayName [rows][cols]elementType // Declare and initialize var arrayName [rows][cols]elementType = [rows][cols]elementType{initialValues}

The following example declares a three-dimensional integer array:

var threedim [5][10][4]int

Two-dimensional array

A two-dimensional array is the simplest multidimensional array. A two-dimensional array is essentially composed of one-dimensional arrays. The way to define a two-dimensional array is as follows:

var arrayName [ x ][ y ] variable_type

variable_type is the data type in Go, arrayName is the array name. A two-dimensional array can be considered a table, with x as rows and y as columns. The following diagram shows a two-dimensional array a with three rows and four columns:

Elements in a two-dimensional array can be accessed viaa[ i ][ j ]to access.

Example

package main

import "fmt"

func main() {
    // Step 1: Create an array
    values := [][]int{}

    // Step 2: Use the append() function to add two rows of one-dimensional arrays to an empty two-dimensional array
    row1 := []int{1, 2, 3}
    row2 := []int{4, 5, 6}
    values = append(values, row1)
    values = append(values, row2)

    // Step 3: Display two rows of data
    fmt.Println("Row 1")
    fmt.Println(values[0])
    fmt.Println("Row 2")
    fmt.Println(values[1])

    // Step 4: Access the first element
    fmt.Println("First element:")
    fmt.Println(values[0][0])
}

The output of the above example is:

Row 1
[1 2 3]
Row 2
[4 5 6]
第一个元素为:
1

Initializing a two-dimensional array

Multidimensional arrays can be initialized with braces. The following example is a two-dimensional array with 3 rows and 4 columns:

a := [3][4]int{  
 {0, 1, 2, 3} ,   /*  第一行索引为 0 */
 {4, 5, 6, 7} ,   /*  第二行索引为 1 */
 {8, 9, 10, 11},   /* 第三行索引为 2 */
}
Note:In the above code, the second-to-last line}must have a comma, because the last line's}It doesn't have to be on a single line; it can also be written like this:
a := [3][4]int{  
 {0, 1, 2, 3} ,   /*  第一行索引为 0 */
 {4, 5, 6, 7} ,   /*  第二行索引为 1 */
 {8, 9, 10, 11}}   /* 第三行索引为 2 */

The following example initializes a two-dimensional array with 2 rows and 2 columns:

Example

package main

import "fmt"

func main() {
    // Create a two-dimensional array
    sites := [2][2]string{}

    // Add elements to the two-dimensional array
    sites[0][0] = "Google"
    sites[0][1] = "Example"
    sites[1][0] = "Taobao"
    sites[1][1] = "Weibo"

    // Display the result
    fmt.Println(sites)
}

The output of the above example is:

[[Google Example] [Taobao Weibo]]

Accessing a two-dimensional array

A two-dimensional array is accessed by specifying coordinates, such as the row index and column index in the array. For example:

val := a[2][3]
或
var value int = a[2][3]

The above example accessed the fourth element in the third row of the two-dimensional array val.

A two-dimensional array can use nested loops to output elements:

Example

package main

import "fmt"

func main() {
   /* Array - 5 rows 2 columns*/
   var a = [5][2]int{ {0,0}, {1,2}, {2,4}, {3,6},{4,8}}
   var i, j int

   /* output array elements */
   for  i = 0; i < 5; i++ {
      for j = 0; j < 2; j++ {
         fmt.Printf("a[%d][%d] = %d\n", i,j, a[i][j] )
      }
   }
}

The output of the above example is:

a[0][0] = 0
a[0][1] = 0
a[1][0] = 1
a[1][1] = 2
a[2][0] = 2
a[2][1] = 4
a[3][0] = 3
a[3][1] = 6
a[4][0] = 4
a[4][1] = 8

The following example creates a multidimensional array where the number of elements in each dimension is inconsistent:

Example

package main

import "fmt"

func main() {
    // Create an empty two-dimensional array
    animals := [][]string{}

    // Create three one-dimensional arrays, each with different lengths
    row1 := []string{"fish", "shark", "eel"}
    row2 := []string{"bird"}
    row3 := []string{"lizard", "salamander"}

    // Use the append() function to add a one-dimensional array to the two-dimensional array
    animals = append(animals, row1)
    animals = append(animals, row2)
    animals = append(animals, row3)

    // Loop to output
    for i := range animals {
        fmt.Printf("Row: %v\n", i)
        fmt.Println(animals[i])
    }
}

The output of the above example is:

Row: 0
[fish shark eel]
Row: 1
[bird]
Row: 2
[lizard salamander]

Accessing and Modifying Array Elements

Access Elements

Example

package main

import "fmt"

func main() {
    // Create a 3x3 matrix
    matrix := [3][3]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }
   
    // Access a single element
    fmt.Println("Row 1, Column 2:", matrix[0][1])  // Output: 2
    fmt.Println("Row 3, Column 3:", matrix[2][2]) // Output: 9
   
    // Access the entire row
    fmt.Println("Row 2:", matrix[1])  // Output: [4 5 6]
   
    // Traverse all elements
    fmt.Println("\nTraverse all elements:")
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf("matrix[%d][%d] = %d\n", i, j, matrix[i][j])
        }
    }
}

modify elements

Example

package main

import "fmt"

func main() {
    // Create a 2x2 zero matrix
    var grid [2][2]int
   
    fmt.Println("Matrix before modification:", grid)
   
    // Modify the element at a specific position
    grid[0][0] = 10
    grid[0][1] = 20
    grid[1][0] = 30
    grid[1][1] = 40
   
    fmt.Println("Matrix after modification:", grid)
   
    // Batch modify a row
    grid[0] = [2]int{100, 200}
    fmt.Println("After modifying the first row:", grid)
}

Three-Dimensional and Higher-Dimensional Arrays

Example of a three-dimensional array

Example

package main

import "fmt"

func main() {
    // Declare a 2x3x4 three-dimensional array
    // Can be understood as: 2 planes, each with 3 rows and 4 columns
    var cube [2][3][4]int
   
    // Initialize 3D array
    cube = [2][3][4]int{
        { // The first plane
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
        },
        { // The second plane
            {13, 14, 15, 16},
            {17, 18, 19, 20},
            {21, 22, 23, 24},
        },
    }
   
    // Access 3D array elements
    fmt.Println("cube[0][1][2] =", cube[0][1][2])  // Output: 7
    fmt.Println("cube[1][2][3] =", cube[1][2][3])  // Output: 24
   
    // Traverse a 3D array
    fmt.Println("\nThree-dimensional array content:)
    for i := 0; i < 2; i++ {
        fmt.Printf("Plane %d:\n", i)
        for j := 0; j < 3; j++ {
            for k := 0; k < 4; k++ {
                fmt.Printf("%3d ", cube[i][j][k])
            }
            fmt.Println()
        }
        fmt.Println()
    }
}

see figure below:


Common Operations on Multidimensional Arrays

1. Iterating with range

Example

package main

import "fmt"

func main() {
    // Create a 2D array
    scores := [3][4]int{
        {85, 90, 78, 92},
        {88, 76, 95, 89},
        {92, 85, 88, 90},
    }
   
    fmt.Println("Student grade table:")
   
    // Use range to iterate over the 2D array
    for i, row := range scores {
        fmt.Printf("Student %d's grades: ", i+1)
        for j, score := range row {
            fmt.Printf("%d ", score)
            // If you need both index and value
            _ = j // Avoid unused variable warning
        }
        fmt.Println()
    }
   
    // Only care about the value, not the index
    total := 0
    count := 0
    for _, row := range scores {
        for _, score := range row {
            total += score
            count++
        }
    }
    fmt.Printf("\nAverage score: %.2f\n", float64(total)/float64(count))
}

2. Getting the Array Length

Example

package main

import "fmt"

func main() {
    // Create an irregular multi-dimensional array
    jagged := [3][3]int{
        {1, 2, 3},
        {4, 5},
        {6, 7, 8, 9}, // Note: This will cause a compilation error because each row must have the same length
    }
   
    // Correct example: Get array dimensions
    matrix := [4][5]int{}
   
    // Get the number of rows
    rows := len(matrix)
    fmt.Println("Rows:", rows)  // Output: 4
   
    // Get the number of columns in the first row (all rows have the same length)
    cols := len(matrix[0])
    fmt.Println("Columns:", cols)  // Output: 5
   
    // Get the total number of elements
    totalElements := rows * cols
    fmt.Println("Total elements:", totalElements)  // Output: 20
}

3. Array comparison

Example

package main

import "fmt"

func main() {
    // Create two identical 2D arrays
    a := [2][2]int{{1, 2}, {3, 4}}
    b := [2][2]int{{1, 2}, {3, 4}}
    c := [2][2]int{{1, 2}, {3, 5}}
   
    // Arrays can be compared directly (only when dimensions are exactly the same)
    fmt.Println("a == b:", a == b)  // Output: true
    fmt.Println("a == c:", a == c)  // Output: false
   
    // Note: Arrays of different dimensions cannot be compared
    // d := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    // fmt.Println(a == d) // Compile error: type mismatch
}

Practical application scenarios

Scenario 1: Game Board (Tic-Tac-Toe)

Example

package main

import "fmt"

func main() {
    // Initialize a 3x3 tic-tac-toe board
    var board [3][3]string
   
    // Initialize as empty
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            board[i][j] = " "
        }
    }
   
    // Simulate moves
    board[0][0] = "X"
    board[1][1] = "O"
    board[2][2] = "X"
   
    // Print the board
    fmt.Println("Tic-tac-toe board:")
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf(" %s ", board[i][j])
            if j < 2 {
                fmt.Printf("|")
            }
        }
        fmt.Println()
        if i < 2 {
            fmt.Println("---+---+---")
        }
    }
}

Scenario 2: Student Grade Management System

Example

package main

import "fmt"

func main() {
    // Define: 3 students, each student has 4 courses
    var grades [3][4]float64
   
    // Input student scores
    grades = [3][4]float64{
        {85.5, 90.0, 78.5, 92.0},  // Student 1's scores
        {88.0, 76.5, 95.0, 89.5},  // Student 2's scores
        {92.5, 85.0, 88.5, 90.0},  // Student 3's scores
    }
   
    // Calculate each student's average score
    fmt.Println("Student score statistics:")
    for i, studentGrades := range grades {
        sum := 0.0
        for _, grade := range studentGrades {
            sum += grade
        }
        average := sum / float64(len(studentGrades))
        fmt.Printf("Student %d: average score = %.2f\n", i+1, average)
    }
   
    // Calculate each course's average score
    fmt.Println("\nCourse average score:")
    for j := 0; j < 4; j++ {
        sum := 0.0
        for i := 0; i < 3; i++ {
            sum += grades[i][j]
        }
        average := sum / 3.0
        fmt.Printf("Course %d: average score = %.2f\n", j+1, average)
    }
}

Scenario 3: Image Pixel Processing

Example

package main

import "fmt"

func main() {
    // Simulate a simple 3x3 grayscale image
    // Each pixel value range: 0(black) ~ 255(white)
    var image [3][3]int
   
    // Initialize the image (a simple gradient)
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            image[i][j] = (i + j) * 50
        }
    }
   
    // Display the original image
    fmt.Println("Original image:")
    displayImage(image)
   
    // Image processing: increase brightness
    fmt.Println("\nImage after brightness increase:")
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            // Increase brightness, but do not exceed 255
            newValue := image[i][j] + 50
            if newValue > 255 {
                newValue = 255
            }
            image[i][j] = newValue
        }
    }
    displayImage(image)
}

func displayImage(img [3][3]int) {
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf("%3d ", img[i][j])
        }
        fmt.Println()
    }
}

Notes and Best Practices

1. Array Length Is Part of the Type

Example

package main

import "fmt"

func main() {
    // These two are different types!
    var a [2][3]int
    var b [3][2]int
   
    // The following code will cause a compilation error
    // a = b // error: type mismatch
   
    fmt.Printf("a's type: %T\n", a)  // [2][3]int
    fmt.Printf("b's type: %T\n", b)  // [3][2]int
}

2. Value Type vs Reference Type

Example

package main

import "fmt"

func main() {
    // Arrays are value types
    original := [2][2]int{{1, 2}, {3, 4}}
   
    // Assignment creates a copy
    copy := original
   
    // Modifying the copy does not affect the original array
    copy[0][0] = 100
   
    fmt.Println("Original array:", original)  // [[1 2] [3 4]]
    fmt.Println("Copy array:", copy)      // [[100 2] [3 4]]
   
    // If you need reference semantics, you can use slices (introduced in later articles)
}

3. Performance considerations

  • Contiguous memory: multidimensional arrays are stored contiguously in memory, providing fast access
  • Fixed size: the length of an array is determined at compile time and cannot be changed dynamically
  • Suitable scenarios: when the data size is known and fixed, arrays are the best choice

Frequently Asked Questions

Q1: What is the difference between a multidimensional array and a nested slice?

Features Multidimensional arrays Nested slices
Size Fixed, determined at compile time Dynamic, variable at runtime
Memory Contiguous allocation Possibly non-contiguous
Performance Fast access speed Slightly slower, has extra overhead
Use Case Data size known Data size variable

Q2: How do you create a ragged two-dimensional array?

Go arrays require each row to have the same length. If you need a ragged structure, you should use slices:

Example

// Use slices to create irregular structures
irregular := [][]int{
    {1, 2, 3},
    {4, 5},          // This line has only 2 elements
    {6, 7, 8, 9},    // This line has 4 elements
}

Q3: Can a multidimensional array be used as a function parameter?

Yes, but note that arrays are value types, and passing large arrays incurs a performance cost:

Example

func processMatrix(matrix [3][3]int) [3][3]int {
    // Process the matrix...
    matrix[0][0] = 100
    return matrix
}

// A better way is to use pointers or slices
func processMatrixPtr(matrix *[3][3]int) {
    matrix[0][0] = 100
}

Go Arrays

other extensions