[go] Golang의 슬라이스에서 요소를 삭제하는 방법

fmt.Println("Enter position to delete::")
fmt.Scanln(&pos)

new_arr := make([]int, (len(arr) - 1))
k := 0
for i := 0; i < (len(arr) - 1); {
    if i != pos {
        new_arr[i] = arr[k]
        k++
        i++
    } else {
        k++
    }
}

for i := 0; i < (len(arr) - 1); i++ {
    fmt.Println(new_arr[i])
}

슬라이스에서 요소를 삭제하기 위해이 명령을 사용하고 있지만 작동하지 않습니다. 제안 해주세요.



답변

주문 문제

배열의 순서를 유지하려면 삭제 인덱스 오른쪽에있는 모든 요소를 ​​왼쪽으로 하나씩 이동해야합니다. 바라건대, 이것은 Golang에서 쉽게 할 수 있습니다 :

func remove(slice []int, s int) []int {
    return append(slice[:s], slice[s+1:]...)
}

그러나 이는 비용이 많이 드는 모든 요소를 ​​이동하게 될 수 있기 때문에 비효율적입니다.

순서는 중요하지 않습니다

순서 지정에 신경 쓰지 않는다면, 삭제할 요소를 슬라이스 끝의 요소로 교체 한 다음 n-1 개의 첫 번째 요소를 반환 할 수있는 훨씬 빠른 가능성이 있습니다.

func remove(s []int, i int) []int {
    s[len(s)-1], s[i] = s[i], s[len(s)-1]
    return s[:len(s)-1]
}

reslicing 방법을 사용하면 1000000 요소의 배열을 비우는 데 224 초가 걸리고이 방법은 0.06ns 만 걸립니다. 내부적으로 go는 수정하지 않고 슬라이스의 길이 만 변경한다고 생각합니다.

편집 1

아래 주석을 기반으로 한 빠른 메모 (감사합니다!).

목적이 요소를 삭제하는 것이므로 순서가 중요하지 않은 경우 단일 스왑이 필요하면 두 번째 스왑이 낭비됩니다.

func remove(s []int, i int) []int {
    s[i] = s[len(s)-1]
    // We do not need to put s[i] at the end, as it will be discarded anyway
    return s[:len(s)-1]
}

또한이 답변은 경계 검사를 수행하지 않습니다. . 입력으로 유효한 색인이 필요합니다. 즉, len (s)보다 크거나 같은 음수 값이나 인덱스는 Go를 패닉 상태로 만듭니다. 슬라이스와 배열이 0 인덱싱되어 배열의 n 번째 요소를 제거하면 입력 n-1 을 제공함을 의미합니다 . 첫번째 요소 콜 제거 제거 (S, 0) , 제 콜 제거 제거 (S 1) , 및 기타 등등.


답변

슬라이스에서 하나의 요소를 제거합니다 (이를 ‘재 슬라이싱’이라고 함).

package main

import (
    "fmt"
)

func RemoveIndex(s []int, index int) []int {
    return append(s[:index], s[index+1:]...)
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println(all) //[0 1 2 3 4 5 6 7 8 9]
    all = RemoveIndex(all, 5)
    fmt.Println(all) //[0 1 2 3 4 6 7 8 9]
}


답변

마이너 포인트 (코드 골프)이지만, 순서가 중요하지 않은 경우 값을 바꿀 필요가 없습니다. 제거되는 배열 위치를 마지막 위치의 복제본으로 덮어 쓴 다음 잘린 배열을 반환하십시오.

func remove(s []int, i int) []int {
    s[i] = s[len(s)-1]
    return s[:len(s)-1]
}

같은 결과.


답변

보기에 약간 이상하지만 여기에있는 대부분의 답변은 위험하고 실제로하는 일에 대해 광택이 없습니다. 조각에서 항목을 제거하는 것에 대해 묻는 원래 질문을 보면 조각의 복사본이 만들어지고 채워지고 있습니다. 이렇게하면 슬라이스가 프로그램 주위로 전달 될 때 미묘한 버그가 발생하지 않습니다.

다음은이 스레드와 원본 게시물의 사용자 답변을 비교하는 코드입니다. 이 코드를 엉망으로 만드는 이동 놀이터 가 있습니다.

추가 기반 제거

package main

import (
    "fmt"
)

func RemoveIndex(s []int, index int) []int {
    return append(s[:index], s[index+1:]...)
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeIndex := RemoveIndex(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9]

    removeIndex[0] = 999
    fmt.Println("all: ", all) //[999 1 2 3 4 6 7 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9]
}

위의 예에서 슬라이스를 만들고 0부터 9까지의 숫자로 수동으로 채울 수 있습니다. 그런 다음 모든 인덱스에서 인덱스 5를 제거하고 인덱스를 제거하도록 할당합니다. 그러나 우리가 지금 모든 것을 인쇄 할 때 우리는 그것이 수정 된 것을 볼 수 있습니다. 슬라이스가 기본 배열에 대한 포인터이기 때문입니다. 에서 더 이상 도달 할 수없는 한 요소에 의해 차이 가 더 길어 지면서 수정되는 removeIndex원인도 작성합니다 . 다음으로 값을 변경 하면 수정되는 것도 볼 수 있습니다. 효과적인 이동allallremoveIndexremoveIndexall 은 이것에 대해 더 자세히 설명합니다.

다음 예제는 다루지 않겠지 만 우리의 목적을 위해 동일한 작업을 수행합니다. 그리고 복사를 사용하는 것이 다르지 않다는 것을 보여줍니다.

package main

import (
    "fmt"
)

func RemoveCopy(slice []int, i int) []int {
    copy(slice[i:], slice[i+1:])
    return slice[:len(slice)-1]
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeCopy := RemoveCopy(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9]
    fmt.Println("removeCopy: ", removeCopy) //[0 1 2 3 4 6 7 8 9]

    removeCopy[0] = 999
    fmt.Println("all: ", all) //[99 1 2 3 4 6 7 9 9]
    fmt.Println("removeCopy: ", removeCopy) //[999 1 2 3 4 6 7 8 9]
}

질문 원래 답변

원래 질문을 보면 항목을 제거하는 조각이 수정되지 않습니다. 이 스레드의 원래 답변은 지금까지이 페이지를 찾는 대부분의 사람들에게 가장 적합합니다.

package main

import (
    "fmt"
)

func OriginalRemoveIndex(arr []int, pos int) []int {
    new_arr := make([]int, (len(arr) - 1))
    k := 0
    for i := 0; i < (len(arr) - 1); {
        if i != pos {
            new_arr[i] = arr[k]
            k++
        } else {
            k++
        }
        i++
    }

    return new_arr
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    originalRemove := OriginalRemoveIndex(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("originalRemove: ", originalRemove) //[0 1 2 3 4 6 7 8 9]

    originalRemove[0] = 999
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("originalRemove: ", originalRemove) //[999 1 2 3 4 6 7 8 9]
}

보시다시피이 출력은 대부분의 사람들이 기대하고 대부분의 사람들이 원하는대로 작동합니다. 수정은 변경을 originalRemove일으키지 않으며 all인덱스를 제거하고 할당하는 작업도 변경을 일으키지 않습니다! 환상적입니다!

이 코드는 약간 길지만 위의 내용을 이것으로 변경할 수 있습니다.

정답

package main

import (
    "fmt"
)

func RemoveIndex(s []int, index int) []int {
    ret := make([]int, 0)
    ret = append(ret, s[:index]...)
    return append(ret, s[index+1:]...)
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeIndex := RemoveIndex(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9]

    removeIndex[0] = 999
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9]
}

원래 인덱스 제거 솔루션과 거의 동일하지만 반환하기 전에 추가 할 새 슬라이스를 만듭니다.


답변

이것이 golang 방식으로 슬라이스 에서 삭제 하는 방법 입니다. append에 내장 된 함수를 빌드 할 필요가 없습니다. 여기에서 시도하십시오 https://play.golang.org/p/QMXn9-6gU5P

z := []int{9, 8, 7, 6, 5, 3, 2, 1, 0}
fmt.Println(z)  //will print Answer [9 8 7 6 5 3 2 1 0]

z = append(z[:2], z[4:]...)
fmt.Println(z)   //will print Answer [9 8 5 3 2 1 0]


답변

The Go Programming Language 책에서

슬라이스 중간에서 요소를 제거하고 나머지 요소의 순서를 유지하려면 copy를 사용하여 더 높은 번호의 요소를 아래로 밀어 간격을 채 웁니다.

func remove(slice []int, i int) []int {
  copy(slice[i:], slice[i+1:])
  return slice[:len(slice)-1]
}


답변

아래 방법을 사용하여 항목을 조각으로 제거합니다. 이것은 다른 사람들의 가독성에 도움이됩니다. 또한 불변합니다.

func remove(items []string, item string) []string {
    newitems := []string{}

    for _, i := range items {
        if i != item {
            newitems = append(newitems, i)
        }
    }

    return newitems
}