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

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

How to delete a key from a complex map?

问题

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

  1. [
  2. {key: "aa", value1: 1, value2: "33"},
  3. {key: "bb", value1: 23, value2: "333"},
  4. {key: "cc", value1: 33, value2: "3366"},
  5. {key: "yy", value1: 99, value2: "666"},
  6. // 其他项
  7. ]

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

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

英文:

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

  1. [
  2. {key: "aa", value1: 1, value2: "33"},
  3. {key: "bb", value1: 23, value2: "333"},
  4. {key: "cc", value1: 33, value2: "3366"},
  5. {key: "yy", value1: 99, value2: "666"},
  6. // other items
  7. ]

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

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

  1. j := 0
  2. for _, v := range mySlice {
  3. if v.key != "bb" && v.key != "yy" {
  4. mySlice[j] = v
  5. j++
  6. }
  7. }
  8. mySlice = mySlice[:j]

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

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

  1. package main
  2. import "fmt"
  3. // filter 函数返回一个切片(重用 m 的底层数组),其中包含 f 返回 true 的所有元素。
  4. func filter[T any](m []T, f func(*T) bool) []T {
  5. j := 0
  6. for i := range m {
  7. if f(&m[i]) {
  8. m[j] = m[i]
  9. j++
  10. }
  11. }
  12. return m[:j]
  13. }
  14. type data struct {
  15. key string
  16. value1 int
  17. value2 string
  18. }
  19. func main() {
  20. xs := []data{
  21. {key: "aa", value1: 1, value2: "33"},
  22. {key: "bb", value1: 23, value2: "333"},
  23. {key: "cc", value1: 33, value2: "3366"},
  24. {key: "yy", value1: 99, value2: "666"},
  25. }
  26. xs = filter(xs, func(x *data) bool { return x.key != "bb" && x.key != "yy" })
  27. fmt.Println(xs)
  28. }
英文:

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

  1. j := 0
  2. for _, v := range mySlice {
  3. if v.key != "bb" && v.key != "yy" {
  4. mySlice[j] = v
  5. j++
  6. }
  7. }
  8. 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.

  1. package main
  2. import "fmt"
  3. // filter returns a slice (reusing the backing array of m), that
  4. // contains all the elements of m for which f returns true.
  5. func filter[T any](m []T, f func(*T) bool) []T {
  6. j := 0
  7. for i := range m {
  8. if f(&m[i]) {
  9. m[j] = m[i]
  10. j++
  11. }
  12. }
  13. return m[:j]
  14. }
  15. type data struct {
  16. key string
  17. value1 int
  18. value2 string
  19. }
  20. func main() {
  21. xs := []data{
  22. {key: "aa", value1: 1, value2: "33"},
  23. {key: "bb", value1: 23, value2: "333"},
  24. {key: "cc", value1: 33, value2: "3366"},
  25. {key: "yy", value1: 99, value2: "666"},
  26. }
  27. xs = filter(xs, func(x *data) bool { return x.key != "bb" && x.key != "yy" })
  28. fmt.Println(xs)
  29. }

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:

确定