Можно ли нарезать внутреннюю матрицу скобками? - PullRequest
4 голосов
/ 29 марта 2019

Я изменяю значения периметра в матрице, затем пытаюсь вернуться во внутренние значения. Я ожидал, что смогу получить доступ к внутренним значениям с помощью 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]. Что происходит?

Детская площадка

Ответы [ 2 ]

1 голос
/ 29 марта 2019

Вот ваши данные:

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] был сублис, а нижележащий срез имел дополнительный элемент.Таким образом, расширив этот подлис, мы можем вернуть этот элемент обратно, а это скрытый элемент 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] равно двумпоследовательные сублицензии.Вместо этого вы берете каждый элемент в срез и извлекаете подлис из каждого элемента. Первый раз, когда вы берете субликсы [1: 3] из [] int {4, 5, 6, 7}.В результате получается

[]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} }
1 голос
/ 29 марта 2019

Когда вы создаете субслайс в 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 имеет только два элемента, но нам разрешено создавать срез второго и третьего элементов, потому что емкость среза, под которым он находится, достаточно велика, и вселомтики разделяют один и тот же базовый массив.См. Последний пример в разделе «Внутренние срезы» на этой странице

Итак, в вашем случае 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]
...