是否可以用括号切割内部矩阵?

问题描述 投票:4回答:2

我正在修改矩阵的周长值,然后尝试递归到内部值。我希望我能用像matrix[1:3][1:3]这样的东西来访问内部值。事实并非如此,而且我对Go处理顺序括号的基本逻辑有点迷失。

package main

import (
    "fmt"
)

var m = [][]int{
    []int{0, 1, 2, 3},
    []int{4, 5, 6, 7},
    []int{8, 9, 10, 11},
    []int{12, 13, 14, 15},
}

我试图访问上面矩阵中的值5,6,9,10,即“内部”矩阵。

func main() {
    inner := m[1:3][1:3]
    fmt.Printf("%#v\n", inner)
    // Expected Output: [][]int{
    // []int{5, 6},
    // []int{9, 10}
    // }
    // Actual Ouput: [][]int{
    // []int{8, 9, 10, 11},
    // []int{12, 13, 14, 15}
    // }
    inner = m[1:3]
    fmt.Printf("%#v\n", inner)
    // Output:
    // [][]int{
    // []int{4, 5, 6, 7},
    // []int{8, 9, 10, 11}
    // }
    inner = innerMatrix(m)
    fmt.Printf("%#v\n", inner)
    // [][]int{
    // []int{5, 6},
    // []int{9, 10}
}

func innerMatrix(m [][]int) (inner [][]int) {
    innerRows := m[1:3]
    for _, row := range innerRows {
        inner = append(inner, row[1:3])
    }
    return
}

函数innerMatrix能够产生我期望的输出。我迷失了为什么(1)m[1:3][1:3]没有相同的效果,(2)它似乎转化为m[2:4]。这是怎么回事?

Playground

go matrix slice
2个回答
1
投票

在Go中创建子切片时,您可以再次将该子切片增加回原始切片的容量,例如:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4, 5}

    b := a[1:3]
    fmt.Printf("a[1:3]: %v\n", b)

    c := b[1:3]
    fmt.Printf("b[1:3]: %v\n", c)
}

哪个输出:

a[1:3]: [2 3]
b[1:3]: [3 4]

请注意,b只有两个元素,但我们允许创建第二个和第三个元素的切片,因为切片的容量是一个子切片足够大,并且所有切片共享相同的底层数组。请参阅this page上“切片内部”一节中的最后一个示例

那么在你的情况下发生的是m[1:3]相当于:

var m1 = [][]int{
    []int{4, 5, 6, 7},   // second element of m
    []int{8, 9, 10, 11}, // third element of m
}

因此,m[1:3][1:3]相当于m1[1:3],相当于:

var m2 = [][]int{
    []int{8, 9, 10, 11},   // second element of m1
    []int{12, 13, 14, 15}, // "third" element of m1
}

出现“第三”元素只是因为m的容量足以容纳它,并且确实包含它。如果m只有三个元素,这会引起恐慌。

换句话说,m[1:3][1:3]在这里完全等同于m[2:4],因为m[1:3][1:3]为你提供了m[1:3]的第二和第三个元素。使用图表可能更容易理解:

m            : []int{1, 2, 3, 4}
m[1:3]       : []int{   2, 3   }
m[1:3][1:3]  : []int{      3, 4}
m[2:4]       : []int{      3, 4}

作为过度简化,你可以想象方括号给出了它们左边的任何东西所要求的元素,所以这是一个有点极端的例子:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4, 5}

    b := a[1:5]
    fmt.Printf("b: %v, a[1:5]               : %v\n",
        b, a[1:5])

    c := b[1:4]
    fmt.Printf("c: %v  , a[1:5][1:4]          : %v\n",
        c, a[1:5][1:4])

    d := c[1:3]
    fmt.Printf("d: %v    , a[1:5][1:4][1:3]     : %v\n",
        d, a[1:5][1:4][1:3])

    e := d[1:2]
    fmt.Printf("e: %v      , a[1:5][1:4][1:3][1:2]: %v\n",
        e, a[1:5][1:4][1:3][1:2])
}

哪个输出:

b: [2 3 4 5], a[1:5]               : [2 3 4 5]
c: [3 4 5]  , a[1:5][1:4]          : [3 4 5]
d: [4 5]    , a[1:5][1:4][1:3]     : [4 5]
e: [5]      , a[1:5][1:4][1:3][1:2]: [5]

1
投票

这是你的数据:

var m = [][]int{
    []int{0, 1, 2, 3},
    []int{4, 5, 6, 7},
    []int{8, 9, 10, 11},
    []int{12, 13, 14, 15},
}

首先你问内在的是什么:= m [1:3] [1:3]?

好吧,一次取一个,m [1:3]是你在抓取元素1到3而不包括3时得到的子片。那就是元素1和2.元素0是[] int {0,1,2, 3},元素1是[] int {4,5,6,7},元素2是[] int {8,9,10,11},

所以m [1:3]是

[][]int{
    []int{4, 5, 6, 7},
    []int{8, 9, 10, 11},
}

现在,为了得到m [1:3] [1:3],我们在这个结果上重复同样的事情。但是,这一次,只有两个要素。我们再次想要元素1和2.我们跳过元素0,即[] int {4,5,6,7}。元素1是[] int {8,9,10,11}。没有元素2.但是,m [1:3]的结果是一个子片段,底层片段有一个额外的元素。所以通过扩展这个子片我们可以再次获得该元素,那就是hiddent元素2,它是[] int {12,13,14,15}。所以m [1:3] [1:3]是

[][]int{
    []int{8, 9, 10, 11},
    [[]int{12, 13, 14, 15},
}

最后,你想知道为什么func innerMatrix的工作方式不同?它首先产生m [1:3]

[][]int{
    []int{4, 5, 6, 7},
    []int{8, 9, 10, 11},
}

然后代码不会以m [1:3] [1:3]是两个连续的子句相同的方式获取另一个子片段。相反,您可以获取切片中的每个元素并从每个元素中获取子切片。第一次通过你从[] int {4,5,6,7}中获取子句[1:3]。结果是

[]int{5, 6}

第二次通过你在第二个元素[] int {8,9,10,11}上做同样的事情

[]int{9, 10} 

最后,每次通过你将结果附加到结果切片,所以你将[] int {5,6}追加到[],给[] [] {int {5,6}},然后你追加[] int {9,10}给

[][]{int{5, 6}, []int{9, 10} }
© www.soinside.com 2019 - 2024. All rights reserved.