Я новичок в Golang, я пытаюсь удалить элементы в одном фрагменте на основе элементов в другом фрагменте. например

Входной срез: urlList := []string{"test", "abc", "def", "ghi"}

Элементы для удаления фрагмента: remove := []string{"abc", "test"}

Ожидаемый выходной фрагмент: urlList := []string{"def", "ghi"}

Это то, что я пробовал.

func main() {

    urlList := []string{"test", "abc", "def", "ghi"}
    remove := []string{"abc", "test"}
loop:
    for i, url := range urlList {
        for _, rem := range remove {
            if url == rem {
                urlList = append(urlList[:i], urlList[i+1:]...)
                continue loop
            }
        }
    }
    for _, v := range urlList {
        fmt.Println(v)
    }
}

Но это работает не так, как я ожидал. Я не знаю, что мне не хватает.

4
Sajan Chandran 24 Фев 2015 в 18:17

5 ответов

Лучший ответ

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

И поскольку список remove содержит 2 элемента, которые расположены рядом друг с другом в исходном списке, второй ("abc" в данном случае) не будет проверяться и будет не удаляться.

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

urlList := []string{"test", "abc", "def", "ghi"}
remove := []string{"abc", "test"}

loop:
for i := 0; i < len(urlList); i++ {
    url := urlList[i]
    for _, rem := range remove {
        if url == rem {
            urlList = append(urlList[:i], urlList[i+1:]...)
            i-- // Important: decrease index
            continue loop
        }
    }
}

fmt.Println(urlList)

Вывод:

[def ghi]

Примечание.

Поскольку внешний цикл после внутреннего цикла ничего не содержит, вы можете заменить метку + continue простым break:

urlList := []string{"test", "abc", "def", "ghi"}
remove := []string{"abc", "test"}

for i := 0; i < len(urlList); i++ {
    url := urlList[i]
    for _, rem := range remove {
        if url == rem {
            urlList = append(urlList[:i], urlList[i+1:]...)
            i-- // Important: decrease index
            break
        }
    }
}

fmt.Println(urlList)

Попробуйте это на Go Playground.

Альтернатива

Альтернативой этому было бы движение внешнего цикла вниз, поэтому нет необходимости вручную уменьшать (или увеличивать) индексную переменную, потому что смещенные элементы не затронуты (уже обработаны из-за направления вниз).

7
icza 24 Фев 2015 в 20:46

В случае индекса:

//RemoveElements delete the element of the indexes contained in j of the data in input
func RemoveElements(data []string, j []int) []string {
    var newArray []string
    var toAdd bool = true
    var removed int = 0
    //sort.Ints(j)
    for i := 0; i < len(data); i++ {
        for _, k := range j {
            // if k < i || k > i {
            //  break
            // } else
            if i == k {
                toAdd = false
                break
            }
        }
        if toAdd {
            newArray = append(newArray, data[i])
            removed++
        }
        toAdd = true
    }
    return newArray
}

Комментарий можно удалить для увеличения производительности, когда срез не такой большой (время сортировки)

0
alessiosavi 3 Ноя 2019 в 14:29

Вы можете использовать эти функции:

func main() {
  array := []string{"A", "B", "C", "D", "E"}
  a = StringSliceDelete(a, 2) // delete "C"
  fmt.Println(a) // print: [A, B, D E]
}

//IntSliceDelete function
func IntSliceDelete(slice []int, index int) []int {
   copy(slice[index:], slice[index+1:])
   new := slice[:len(slice)-1]
   return new
}

//StringSliceDelete function
func StringSliceDelete(slice []string, index int) []string {
    copy(slice[index:], slice[index+1:])
    new := slice[:len(slice)-1]
    return new
}

// ObjectSliceDelete function
func ObjectSliceDelete(slice []interface{}, index int) []interface{} {
    copy(slice[index:], slice[index+1:])
    new := slice[:len(slice)-1]
    return new
}
0
LEMUEL ADANE 28 Окт 2018 в 06:46

Вы должны быть осторожны при изменении среза во время итерации по нему.

Вот обычный способ удаления элементов из среза путем сжатия данных во время итерации по ним.

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

Exclude обновляет xs на месте, поэтому используется аргумент указателя. Альтернативой может быть обновление массива поддержки xs, но возврат фрагмента из функции таким же образом, как работает встроенный append.

package main

import "fmt"

func Exclude(xs *[]string, excluded map[string]bool) {
    w := 0
    for _, x := range *xs {
        if !excluded[x] {
            (*xs)[w] = x
            w++
        }
    }
    *xs = (*xs)[:w]
}

func mapFromSlice(ex []string) map[string]bool {
    r := map[string]bool{}
    for _, e := range ex {
        r[e] = true
    }
    return r
}

func main() {
    urls := []string{"test", "abc", "def", "ghi"}
    remove := mapFromSlice([]string{"abc", "test"})
    Exclude(&urls, remove)
    fmt.Println(urls)
}

Этот код - O (N + M) во время выполнения, где N - длина urls, а M - длина remove.

1
Paul Hankin 25 Фев 2015 в 08:11

Возможно, проще создать новый фрагмент, содержащий только желаемые элементы, например:

package main

import "fmt"

func main() {
    urlList := []string{"test", "abc", "def", "ghi"}
    remove := []string{"abc", "test"}

    new_list := make([]string, 0)

    my_map := make(map[string]bool, 0)
    for _, ele := range remove {
        my_map[ele] = true
    }

    for _, ele := range urlList {
        _, is_in_map := my_map[ele]
        if is_in_map {
            fmt.Printf("Have to ignore : %s\n", ele)
        } else {
            new_list = append(new_list, ele)    
        }
    }

    fmt.Println(new_list)

}

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

Результат:

Have to ignore : test
Have to ignore : abc
[def ghi]
2
Akavall 24 Фев 2015 в 16:26