Remove element by value in Go list

huangapple go评论92阅读模式
英文:

Remove element by value in Go list

问题

我有一个元素列表,我想通过值来删除其中一个元素。在Python中,可以这样做:

l = ["apples", "oranges", "melon"]
l.remove("melon")
print(l) # ["apples", "oranges"]

在Go语言中,有一个slice技巧可以通过索引来删除元素,但它不太易读,仍然需要手动找到索引,并且只适用于单个项目类型:

func remove(l []string, item string) {
    for i, other := range l {
        if other == item {
            return append(l[:i], l[i+1:]...)
        }
    }
}

还有list.List结构,但它不是通用的,因此需要大量的类型转换才能使用。

从列表中删除元素的惯用方法是什么?

英文:

I have a list of elements and I want to remove one of them, by value. In Python this would be

l = ["apples", "oranges", "melon"]
l.remove("melon")
print(l) # ["apples", "orange"]

What is the equivalent in Go? I found a slice trick to remove an element by index, but it's not very readable, still requires me to find the index manually and only works for a single item type:

func remove(l []string, item string) {
    for i, other := range l {
        if other == item {
        	return append(l[:i], l[i+1:]...)
        }
    }
}

There's the list.List structure, but it's not generic and thus requires tons of type-castings to use.

What is the idiomatic way of removing an element from a list?

答案1

得分: 23

从列表中删除元素的惯用方法是像你在示例中所做的那样循环遍历它。从切片中按值删除元素在程序中不应该太常见,因为它是一个O(n)的操作,并且语言中有更好的数据结构来处理这个问题。因此,Go语言没有为切片提供内置的删除函数。

如果你经常使用按值删除元素,请考虑使用集合(set)代替,其中删除和添加元素的时间复杂度为O(1),同时仍然可以进行迭代。

set := map[string]bool{"apples": true, "oranges": true, "melon": true}
delete(set, "melon") // 时间复杂度为O(1)
英文:

The idiomatic way to remove an element from a list is to loop through it exactly like you do in your example. Removing an element by value from a slice shouldn't be too common in your program since it is an O(n) operation and there are better data structures in the language for that. Therefore, Go does not provide a built-in remove function for slices.

If you find yourself using removal by value often, consider using a set instead where removing and adding an element is O(1) while still being iterable.

set := map[string]bool{"apples":true, "oranges":true, "melon":true}
delete(set,"melon") // is O(1)

答案2

得分: 7

在通用的Go语言(1.18)中,filter函数适用于任何comparable类型。它只会删除第一个出现的项目。

func remove[T comparable](l []T, item T) []T {
    for i, other := range l {
        if other == item {
            return append(l[:i], l[i+1:]...)
        }
    }
    return l
}

Playground: https://go.dev/play/p/ojlYkvf5dQG?v=gotip

如果你想删除所有出现的项目,可以将不匹配的项目追加到一个新的切片中:

func remove[T comparable](l []T, item T) []T {
    out := make([]T, 0)
    for _, element := range l {
        if element != item {
            out = append(out, element)
        }
    }
    return out
}

Playground: https://go.dev/play/p/W2MerNbh72H

如果切片中的项目不可比较,你可以使用自定义的相等函数进行过滤:

func main() {
    list := [][]int{{1, 2}, {2, 2}, {1, 10}}
    newlist := remove(list, func(element []int) bool { return element[0] == 1 })
    fmt.Println(newlist)
}

func remove[T any](l []T, remove func(T) bool) []T {
    out := make([]T, 0)
    for _, element := range l {
        if !remove(element) {
            out = append(out, element)
        }
    }
    return out
}

Playground: https://go.dev/play/p/qZWoFbM_RUl

英文:

In generic Go (1.18) the filter function works on any comparable type. It removes only the first occurrence of the item.

func remove[T comparable](l []T, item T) []T {
    for i, other := range l {
        if other == item {
            return append(l[:i], l[i+1:]...)
        }
    }
    return l
}

Playground: https://go.dev/play/p/ojlYkvf5dQG?v=gotip

<hr>

If you want to remove all occurrences, append the items that don't match to a new slice:

func remove[T comparable](l []T, item T) []T {
	out := make([]T, 0)
	for _, element := range l {
		if element != item {
			out = append(out, element)
		}
	}
	return out
}

Playground: https://go.dev/play/p/W2MerNbh72H

<hr>

If the slice items aren't comparable, you can use a custom equality function to filter:

func main() {
	list := [][]int{{1, 2}, {2, 2}, {1, 10}}
	newlist := remove(list, func(element []int) bool { return element[0] == 1 })
	fmt.Println(newlist)
}

func remove[T any](l []T, remove func(T) bool) []T {
	out := make([]T, 0)
	for _, element := range l {
		if !remove(element) {
			out = append(out, element)
		}
	}
	return out
}

Playground: https://go.dev/play/p/qZWoFbM_RUl

huangapple
  • 本文由 发表于 2015年6月27日 02:55:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/31080285.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定