Что такое идиома Go для метода Python list.pop ()? - PullRequest
0 голосов
/ 28 сентября 2018

В Python у меня есть следующее:

i = series.index(s) # standard Python list.index() function
tmp = series.pop(i)
blah = f(tmp)
series.append(tmp)

Преобразовывая это в Go, я ищу аналогичный способ получения элемента из слайса по индексу, что-то с ним делать, затем помещаяисходный элемент в конце моего фрагмента.

Начиная с здесь , я пришел к следующему:

i = Index(series, s) // my custom index function...
tmp, series = series[i], series[i+1:]
blah := f(tmp)
series = append(series, tmp)

Но в конце списков ничего не получается:

panic: runtime error: slice bounds out of range

Как бы я идиоматически перевел это slice.pop() на Go?

Ответы [ 5 ]

0 голосов
/ 30 сентября 2018

Вы можете объявить type intSlice []int, и вы можете объявить метод pop() с помощью этого получателя указателя: func (l *intSlice) pop() int.Затем вы можете вызвать .pop() в случае объекта intSlice.Это стилистически больше похоже на Python.

package main

import (
    "fmt"
)

type intSlice []int

func (l *intSlice) pop() int {
    length := len(*l)
    lastEle := (*l)[length-1]
    *l = (*l)[:length-1]
    return lastEle
}

func main() {

    mySlice := intSlice{1, 2, 3, 4, 5, 6}

    popped := mySlice.pop()

    fmt.Println(popped)
    fmt.Println(mySlice)

    popped = mySlice.pop()

    fmt.Println(popped)
    fmt.Println(mySlice)

}

Результат:

6
[1 2 3 4 5]
5
[1 2 3 4]

Go Playground

0 голосов
/ 28 сентября 2018

Если вы хотите написать функцию, которая выполняет pop () аналогично python, вам нужно будет передать указатель на объект, чтобы объект мог быть изменен, так как pop возвращает значение и изменяетсписок

func pop(alist *[]int) int {
   f:=len(*alist)
   rv:=(*alist)[f-1]
   *alist=append((*alist)[:f-1])
   return rv
}

func main() {
n:=[]int{1,2,3,4,5}
fmt.Println(n)
last:=pop(&n)
fmt.Println("last is",last)
fmt.Printf("list of n is now %v\n", n)
0 голосов
/ 28 сентября 2018

Я бы сделал нечто похожее на то, что предложил paulsm4:

package main

import (
    "fmt"
)

func main() {
    a := []int{1,2,3,4,5}
    i,b := pop(a)
    fmt.Println(i,b) // 5 [1 2 3 4]
}

func pop(a []int) (int,[]int) {
    return a[len(a)-1],a[:len(a)-1]
}

Игровая площадка

0 голосов
/ 28 сентября 2018

Трюк «Вырезать» в связанном документе делает то, что вы хотите:

xs := []int{1, 2, 3, 4, 5}

i := 0 // Any valid index, however you happen to get it.
x := xs[i]
xs = append(xs[:i], xs[i+1:]...)
// Now "x" is the ith element and "xs" has the ith element removed.

Обратите внимание, что если вы попытаетесь сделать однострочную из получения иОперации вырезания дают неожиданные результаты из-за сложного поведения нескольких присваиваний, в которых функции вызываются до того, как другие выражения будут оцениваться :

i := 0
x, xs := xs[i], append(xs[:i], xs[i+1:]...)
// XXX: x=2, xs=[]int{2, 3, 4, 5}

Обойти элемент можно, обернув элементоперация доступа в любом вызове функции, например, функция идентификации:

i := 0
id := func(z int) { return z }
x, xs := id(xs[i]), append(xs[:i], xs[i+1:]...)
// OK: x=1, xs=[]int{2, 3, 4, 5}

Однако в этот момент, вероятно, более понятно использовать отдельные назначения.

Для полноты, функция "cut"и его использование может выглядеть так:

func cut(i int, xs []int) (int, []int) {
  y := xs[i]
  ys := append(xs[:i], xs[i+1:]...)
  return y, ys
}

t, series := cut(i, series)
f(t)
series = append(series, t)
0 голосов
/ 28 сентября 2018

Я не уверен, что есть прямой эквивалент "pop ()" ... но вы можете сделать что-то вроде этого:

Тур по Го

Срезы можно создавать с помощью встроенной функции make;это то, как вы создаете массивы динамического размера.

Функция make выделяет обнуленный массив и возвращает фрагмент, который ссылается на этот массив:

a := make([]int, 5) // len(a)=5

Чтобы указатьемкость, передайте третий аргумент, чтобы сделать:

b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5

b = b[1:] // len(b)=4, cap(b)=4

См. также:

...