슬라이스에서 요소 삭제


139
func main() {
    a := []string{"Hello1", "Hello2", "Hello3"}
    fmt.Println(a)
    // [Hello1 Hello2 Hello3]
    a = append(a[:0], a[1:]...)
    fmt.Println(a)
    // [Hello2 Hello3]
}

추가 기능을 사용하면 삭제 트릭이 어떻게 작동합니까?

첫 번째 요소 (빈 배열) 전에 모든 것을 잡는 것처럼 보입니다.

그런 다음 첫 번째 요소 뒤에 모든 것을 추가하십시오 (위치 0)

... (도트 도트 도트)의 기능은 무엇입니까?



3
언어 사양을 보시지 않겠습니까? ...자세히 설명되어 있습니까?
Volker

9
한편으로는 절대적으로 사실입니다 ( golang.org/ref/spec , 모두); 다른 한편으로는, 다른 사람들이 찾을 수있는 파이썬 스타 등을 이주시키기위한이 관용구에 대해 충분히 익숙하지 않습니다.
twotwotwo

답변:


276

a슬라이스는 어디에 있고 i삭제할 요소의 인덱스는 다음 과 같습니다.

a = append(a[:i], a[i+1:]...)

... Go의 variadic 인수에 대한 구문입니다.

기본적으로 함수를 정의 할 때 전달 하는 모든 인수를 해당 유형의 한 조각에 넣습니다. 그렇게하면 원하는만큼 많은 인수를 전달할 수 있습니다 (예 : 원하는 fmt.Println만큼 많은 인수를 취할 수 있음).

이제 함수를 호출 할 때 ...반대가 수행됩니다. 슬라이스의 압축을 풀고 별도의 인수로 변수를 가변 함수에 전달합니다.

이 라인이하는 일 :

a = append(a[:0], a[1:]...)

본질적으로 :

a = append(a[:0], a[1], a[2])

이제 궁금 할 수도 있습니다.

a = append(a[1:]...)

음의 함수 정의 append

func append(slice []Type, elems ...Type) []Type

따라서 첫 번째 인수는 올바른 유형의 슬라이스 여야하고 두 번째 인수는 가변적이므로 빈 슬라이스를 전달한 다음 나머지 슬라이스의 압축을 풀어 인수를 채 웁니다.


35
i가 슬라이스의 마지막 요소 인 경우 범위를 벗어나지 않습니까? a = append(a[:i], a[i+1:]...)
themihai

5
/ : 내 프로젝트 내 조각 작업을 할 때 @DaveC 그 오류를받을 수 있나요
Tyguy7

3
사양의 @ Tyguy7 : "배열 또는 문자열의 경우 인덱스는 0 <= low <= high <= len (a)이면 범위에 있고 그렇지 않으면 범위를 벗어납니다." 어쩌면 귀하의 경우 높음 <낮음; 이 경우 오류가 발생합니다. ( golang.org/ref/spec#Slice_expressions )
mlg

2
이것의 성능은 어떻습니까? 나는 그것이 후드 아래 완전히 새로운 슬라이스를 생성하지 않기를 진심으로 바랍니다 ..
joonas.fi

7
@ Tyguy7 루프 내에서 슬라이스 요소를 삭제하려고했다고 생각합니다. 따라서 색인에주의해야합니다.
Nikolay Bystritskiy

42

두 가지 옵션이 있습니다.

A : 배열 순서 유지에 관심이 있습니다.

a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]

B : 당신은 질서를 유지하는 것에 신경 쓰지 않는다 (아마 더 빠를 것이다) :

a[i] = a[len(a)-1] // Replace it with the last one. CAREFUL only works if you have enough elements.
a = a[:len(a)-1]   // Chop off the last one.

배열이 포인터 인 경우 메모리 누수에 대한 영향을 보려면 링크를 참조하십시오.

https://github.com/golang/go/wiki/SliceTricks


이것은 흥미롭지 만 실제로 질문에 대답하지는 않습니다.
Bryan

이것은 좋지만 배열에서 유일한 요소를 삭제할 수 있다면 더 좋을 것입니다
Naguib Ihab

2
슬라이스에서 마지막 요소를 제거하려고하면 b에서 첫 번째 요소 (마지막 요소로 교체)를 사용하려고 시도한 것이 확실하게 작동하지 않습니다. lol
Sirens

13

[a:]-, [:b]-및 -표시 의 색인 [a:b]을 요소 색인으로 생각하는 대신 요소 주변 및 사이의 간격의 0색인으로 생각하십시오 0.

여기에 이미지 설명을 입력하십시오

그냥 파란색 숫자를 보면, 그것은에 무슨 일이 일어나고 있는지 볼 훨씬 쉽게 : [0:3]은 분리 장치의 모든 것을 [3:3]비어 있고 [1:2]얻을 것이다 {"B"}. 그러면 [a:]짧은 버전 [a:len(arrayOrSlice)], [:b]짧은 버전 [0:b][:]짧은 버전이 [0:len(arrayOrSlice)]있습니다. 후자는 일반적으로 필요할 때 배열을 슬라이스로 변환하는 데 사용됩니다.


1
이는 i 번째 요소를 참조 할 때에도 [i + 1 :]을 참조하여 dave의 답변에 대한 themihai의 의견 에 대한 답변이 "아니오"인 이유를 설명하는 데 도움이됩니다 . play.golang.org/p/E0lQ3jPcjX5
Nick P

5

... 가변 인수에 대한 구문입니다.

나는 그것이 []Type)append 함수와 같이 slice ( )를 사용하여 컴파일러에 의해 구현되었다고 생각합니다 .

func append(slice []Type, elems ...Type) []Type

"append"에서 "elems"를 사용할 때 실제로는 slice ([] type)입니다. " a = append(a[:0], a[1:]...)"는 " a = append(a[0:0], a[1:])"을 의미합니다

a[0:0] 아무것도없는 슬라이스입니다

a[1:] "Hello2 Hello3"입니다.

이것이 작동하는 방법입니다


2
a[0:0]nil길이가 0 인 슬라이스 가 아닙니다 . a[0:0]것이다 에만 있을 nil경우 a입니다 nil.
icza

5

허용되는 답변 솔루션으로 색인이 범위를 벗어났습니다. 이유 : 범위 시작시 값을 하나씩 반복하지 않고 인덱스별로 반복합니다. 슬라이스가 범위 내에있는 동안 슬라이스를 수정하면 문제가 발생할 수 있습니다.

기존 답변 :

chars := []string{"a", "a", "b"}

for i, v := range chars {
    fmt.Printf("%+v, %d, %s\n", chars, i, v)
    if v == "a" {
        chars = append(chars[:i], chars[i+1:]...)
    }
}
fmt.Printf("%+v", chars)

예상 :

[a a b], 0, a
[a b], 0, a
[b], 0, b
Result: [b]

실제 :

// Autual
[a a b], 0, a
[a b], 1, b
[a b], 2, b
Result: [a b]

올바른 방법 (솔루션) :

chars := []string{"a", "a", "b"}

for i := 0; i < len(chars); i++ {
    if chars[i] == "a" {
        chars = append(chars[:i], chars[i+1:]...)
        i-- // form the remove item index to start iterate next item
    }
}

fmt.Printf("%+v", chars)

출처 : https://dinolai.com/notes/golang/golang-delete-slice-item-in-range-problem.html


3

golang의 위키에서는 슬라이스에서 요소 삭제를 포함하여 슬라이스에 대한 몇 가지 트릭을 보여줍니다.

링크 : 여기에 링크 설명을 입력하십시오

예를 들어 a는 숫자 i 요소를 삭제하려는 슬라이스입니다.

a = append(a[:i], a[i+1:]...)

또는

a = a[:i+copy(a[i:], a[i+1:])]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.