DEV Community

Linive
Linive

Posted on

Slice multi-dimensional

Vocês lembram dos slices? Ele se parece com uma linha.

Alt Text

Agora imagine uma pilha com vários slices, um em cima do outro.

Alt Text

Esse exemplo é de um slice com duas dimensões, e é dele que vamos falar hoje.

Olhando para foto é possível perceber que um slice 2d é semelhante a uma tabela, com linhas e colunas, assim como no Excel. Não podemos esquecer disso.

Declarando um slice multi-dimensional

var tabela = [][]int{
    []int{1, 2, 3, 4},
    []int{5, 6, 7, 8},
    []int{9, 10, 11, 12},
}

var sl = []int{40, 41, 42, 43} //Slice comum 

A declaração não é tão diferente. Temos o nome da nossa variável, os colchetes e o tipo dos valores que serão armazenados.

A primeira diferença é que temos dois pares de colchetes [][]int. Isso irá indicar que nosso slice tem duas dimensões, podemos colocar várias outras.

Um slice 2d é composto por vários slices comuns empilhados, semelhante a uma tabela. E é exatamente isso que foi feito, colocamos vários slices dentro do nosso slice bidimensional.

É assim que devemos enxergar a tabela que criamos:

Alt Text

Essa tabela possui linhas e colunas. Através delas conseguiremos pegar um elemento de forma individual.

var tabela = [][]int{

     colunas:  0  1  2  3
linha: 0 []int{1, 2, 3, 4},
linha: 1 []int{5, 6, 7, 8},
linha: 2 []int{9, 10, 11, 12},
} 

Para identificar um único valor, vamos utilizar o padrão:
[linha][coluna].

Alt Text

var tabela = [][]int{

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

fmt.Println(tabela[0][2], tabela[2][3])

//Resultado: 3 12

Loops

Vamos testar o for range na nossa tabela.

var tabela = [][]int{

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

for indice, valor := range tabela{
    fmt.Println(indice, valor)
}

/*Resultado: 
0 [1 2 3 4]
1 [5 6 7 8]
2 [9 10 11 12]
*/

O índice retorna o índice das linhas, já o valor retorna todo o slice que corresponde aquele índice.

E se quisermos demonstrar cada valor de cada slice de forma individual?

Vamos ter que fazer outro loop, desta vez percorrendo elemento por elemento de cada slice.

Sabe quem retorna todos os elemento unidos da slice? O valor. Só que ele retorna todos os valores juntos, por isso vamos fazer um loop for nele.

var tabela = [][]int{

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

for indice, valor := range tabela{
    fmt.Println("Linha:",indice)

    for i, numero := range valor{
        fmt.Println("\tcoluna:", i, "Numero:", numero)
    }
}

/*Resultado: 
Linha: 0
        coluna: 0 Numero: 1
        coluna: 1 Numero: 2
        coluna: 2 Numero: 3
        coluna: 3 Numero: 4
Linha: 1
        coluna: 0 Numero: 5
        coluna: 1 Numero: 6
        coluna: 2 Numero: 7
        coluna: 3 Numero: 8
Linha: 2
        coluna: 0 Numero: 9
        coluna: 1 Numero: 10
        coluna: 2 Numero: 11
        coluna: 3 Numero: 12
*/

Também conseguimos fazer com o for normal.

var tabela = [][]int{

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

for indice := 0; indice < len(tabela); indice++ {
    fmt.Println(indice, tabela[indice]) 
}

/*Resultado: 
0 [1 2 3 4]
1 [5 6 7 8]
2 [9 10 11 12]
*/

O len(tabela) vai percorrer os índices das linhas, por isso que tabela[indice] retorna o slice completo. Se quisermos percorrer elemento por elemento, vamos ter que fazer outro loop.

var tabela = [][]int{

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

for indice := 0; indice < len(tabela); indice++ {
    fmt.Println("Linha:", indice)

    for c := 0; c < len(tabela[indice]); c++ {
        fmt.Println("\tcoluna:", i, "Numero:", tabela[indice][i])
    }
}

/*Resultado: 
Linha: 0
        coluna: 0 Numero: 1
        coluna: 1 Numero: 2
        coluna: 2 Numero: 3
        coluna: 3 Numero: 4
Linha: 1
        coluna: 0 Numero: 5
        coluna: 1 Numero: 6
        coluna: 2 Numero: 7
        coluna: 3 Numero: 8
Linha: 2
        coluna: 0 Numero: 9
        coluna: 1 Numero: 10
        coluna: 2 Numero: 11
        coluna: 3 Numero: 12
*/

A tabela[indice] contém todo o nosso slice, então fizemos um loop com o seu length, len(tabela[indice]).

Para selecionar um elemento do loop devemos ter a informação da linha e da coluna tabela[linha][coluna]. A linha esta contida no indice, tabela[indice], a coluna irá ser "c", tabela[indice][c].

Caso fiquem confusos com tanto loop 👇🏼

Make

Caso não tenha lido o post sobre slices, basicamente o make nos permite criar slices com uma capacidade máxima.

var tabela = make([][]int, 3, 10)

fmt.Println(tabela, len(tabela), cap(tabela))

//Resultado: [[] [] []] 3 10

make([][]int, 3, 10). Esse 3 será o length das linhas, ele já criou espaço para 3 slices no meu slice 2d. Mas como ainda não atribuímos nenhum valor, eles estão vazios.

Existem algumas formas de atribuir valor:

var tabela = make([][]int, 3, 10)

//Primeira
sl:= []int{1, 2, 3, 4}
tabela[0] = sl

//Segunda
tabela[1] = []int{5, 6, 7, 8}

fmt.Println(tabela, len(tabela), cap(tabela))

//Resultado: [[1 2 3 4] [5 6 7 8] []] 3 10

Vamos supor que já preenchemos nossos espaços disponível, agora vamos ter que adicionar novos elementos com o append.

Lembrando que uma slice 2d é formado por outras slices, então não podemos dar um append em números isolados int. Nossa tabela só receberá elementos do tipo []int, slice of int.

var tabela = make([][]int, 3, 10)

tabela[0] = []int{1, 2, 3, 4}
tabela[1] = []int{1, 2, 3, 4}
tabela[2] = []int{5, 6, 7, 8}
fmt.Println(tabela, len(tabela), cap(tabela))

sl := []int{9, 10, 11, 12}
tabela = append(tabela, sl)
fmt.Println(tabela, len(tabela), cap(tabela))

tabela = append(tabela,[]int{13, 14, 15, 16})
fmt.Println(tabela, len(tabela), cap(tabela))

/*Resultado: 
[[1 2 3 4] [1 2 3 4] [5 6 7 8]] 3 10
[[1 2 3 4] [1 2 3 4] [5 6 7 8] [9 10 11 12]] 4 10
[[1 2 3 4] [1 2 3 4] [5 6 7 8] [9 10 11 12][13 14 15 16]] 5 10
*/

Por hoje é isso, espero que tenham entendido e testem bastante.

Caso queiram se aprofundar em go 👉🏼 vamo nessa

Alt Text

Top comments (0)