如何从复杂的映射中删除一个键?

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

How to delete a key from a complex map?

问题

我知道delete(...)函数的用法。但是我有一个包含多个映射的数组:

[
  {key: "aa", value1: 1, value2: "33"},
  {key: "bb", value1: 23, value2: "333"},
  {key: "cc", value1: 33, value2: "3366"},
  {key: "yy", value1: 99, value2: "666"},
  // 其他项
]

我该如何从这个结构中删除具有特定key的项?比如说,key == "bb"key == "yy"

请注意,这个数组的实际大小更大,可能有几十个或几百个项。因此,我希望有一个高效的解决方案。

英文:

I'm aware of the function delete(...). But I have an array of maps:

[
  {key: "aa", value1: 1, value2: "33"},
  {key: "bb", value1: 23, value2: "333"},
  {key: "cc", value1: 33, value2: "3366"},
  {key: "yy", value1: 99, value2: "666"},
  // other items
]

How would I delete the items from this structure which have certain key-s ? Let's say, key == "bb" and key == "yy"

Note that the real size of this array is bigger - dozens or hundreds of items. As such, I'd prefer a performant solution.

答案1

得分: 0

你可以使用一个常见的技巧,在迭代过程中将元素向下移动,然后在最后进行截断。

j := 0
for _, v := range mySlice {
    if v.key != "bb" && v.key != "yy" {
        mySlice[j] = v
        j++
    }
}
mySlice = mySlice[:j]

这种方法使用了 O(1) 的额外内存,并且效率很高。

在 go1.18 中,你将能够编写一个通用函数(通常称为 filter),来执行切片操作。下面是一个完整的示例,你也可以在 gotip playground 上运行它

package main

import "fmt"

// filter 函数返回一个切片(重用 m 的底层数组),其中包含 f 返回 true 的所有元素。
func filter[T any](m []T, f func(*T) bool) []T {
    j := 0
    for i := range m {
        if f(&m[i]) {
            m[j] = m[i]
            j++
        }
    }
    return m[:j]
}

type data struct {
    key    string
    value1 int
    value2 string
}

func main() {
    xs := []data{
        {key: "aa", value1: 1, value2: "33"},
        {key: "bb", value1: 23, value2: "333"},
        {key: "cc", value1: 33, value2: "3366"},
        {key: "yy", value1: 99, value2: "666"},
    }
    xs = filter(xs, func(x *data) bool { return x.key != "bb" && x.key != "yy" })
    fmt.Println(xs)
}
英文:

You can use a standard trick of moving things down in the slice as you iterate, and then truncating at the end.

j := 0
for _, v := range mySlice {
    if v.key != "bb" && v.key != "yy" {
        mySlice[j] = v
        j++
    }
}
mySlice = mySlice[:j]

This uses O(1) extra memory, and is efficient.

In go1.18, you'll be able to write a generic function (which is typically called filter) to do the slicing. Here's a complete example, which you can also run on the gotip playground.

package main

import "fmt"

// filter returns a slice (reusing the backing array of m), that
// contains all the elements of m for which f returns true.
func filter[T any](m []T, f func(*T) bool) []T {
	j := 0
	for i := range m {
		if f(&m[i]) {
			m[j] = m[i]
			j++
		}
	}
	return m[:j]
}

type data struct {
	key    string
	value1 int
	value2 string
}

func main() {
	xs := []data{
		{key: "aa", value1: 1, value2: "33"},
		{key: "bb", value1: 23, value2: "333"},
		{key: "cc", value1: 33, value2: "3366"},
		{key: "yy", value1: 99, value2: "666"},
	}
	xs = filter(xs, func(x *data) bool { return x.key != "bb" && x.key != "yy" })
	fmt.Println(xs)
}

huangapple
  • 本文由 发表于 2021年12月15日 20:39:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/70363851.html
匿名

发表评论

匿名网友

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

确定