【问题标题】:Finding Unique Items in a Go Slice or Array在 Go 切片或数组中查找唯一项
【发布时间】:2015-12-05 22:06:59
【问题描述】:

我还是个新手,我现在真的很困惑。

假设我有一个坐标列表,假设我在这个坐标列表中有一些双精度数。我一辈子都想不出如何制作一个独特的清单。通常在 Python 中,我可以用集合和其他内置函数“作弊”。在 Go 中没有那么多。

package main

import (
    "fmt"
    "reflect"
)

type visit struct {
    x, y int
}

func main() {
    var visited []visit
    var unique []visit

    visited = append(visited, visit{1, 100})
    visited = append(visited, visit{2, 2})
    visited = append(visited, visit{1, 100})
    visited = append(visited, visit{1, 1})

    unique = append(unique, visit{1, 1})

    fmt.Println(unique)

    // Go through the visits and find the unique elements
    for _, v := range visited {
        for _, u := range unique {

            fmt.Printf("Here's unique: %v\n", unique)
            fmt.Printf("Comparing %v to %v is %v\n", v, u, reflect.DeepEqual(v, u))

            if reflect.DeepEqual(v, u) {
                fmt.Println("Skip")
            } else {
                unique = append(unique, v)
            }
        }
    }

    fmt.Println(unique)
}

Run it on Playground

【问题讨论】:

  • 如果您希望列表仅包含唯一条目,您通常可以执行map[string]struct{}{} 之类的操作。空结构不占用任何内存。

标签: arrays go set unique slice


【解决方案1】:

您的代码中有多个错误。最严重的是,由于您将visited 切片的每个特定元素与unique所有 元素进行比较,如果unique 至少包含一个这是不同的。展望未来,如果unique 中有更多元素不同,您最终将多次附加它,因为您的内部for 循环不会“中断”。这不是你想要的,你想附加等于 none of unique 的元素。

还要注意,如果每个字段都可比较,则 Go 中的 struct 是可比较的。由于您的 visit 结构仅包含 2 个 int 字段,因此它具有可比性,因此您可以简单地使用 == 运算符比较 visit 类型的值,不需要那个丑陋的 reflect.DeepEqual()。见Spec: Comparison operators

如果结构的所有字段都是可比较的,那么结构值是可比较的。如果对应的非blank 字段相等,则两个结构值相等。

这是一个应用您的逻辑的简化、正确的版本:

visited := []visit{
    visit{1, 100},
    visit{2, 2},
    visit{1, 100},
    visit{1, 1},
}
var unique []visit

for _, v := range visited {
    skip := false
    for _, u := range unique {
        if v == u {
            skip = true
            break
        }
    }
    if !skip {
        unique = append(unique, v)
    }
}

fmt.Println(unique)

输出(在Go Playground 上试试):

[{1 100} {2 2} {1 1}]

另类

Go 确实没有内置的 set 类型,但您可以轻松地将 map[visit]bool 用作 set。有了它,它变得非常简单!请注意,visit 可以用作映射中的键,因为它具有可比性(见上文)。

visited := []visit{
    visit{1, 100},
    visit{2, 2},
    visit{1, 100},
    visit{1, 1},
}
unique := map[visit]bool{}

for _, v := range visited {
    unique[v] = true
}

fmt.Println(unique)

输出(在Go Playground 上试试):

map[{2 2}:true {1 1}:true {1 100}:true]

唯一的“列表”是映射中的键列表。

如果您希望将唯一的 visit 值作为切片,请参阅此变体:

var unique []visit
m := map[visit]bool{}

for _, v := range visited {
    if !m[v] {
        m[v] = true
        unique = append(unique, v)
    }
}

fmt.Println(unique)

输出(如预期的那样,在Go Playground上试试):

[{1 100} {2 2} {1 1}]

请注意,如果v 已经在映射中(作为键,true 是我们存储在映射中的值),则此索引表达式:m[v] 的计算结果为 true。如果v 尚未在映射中,则m[v] 产生值类型的零值,即false 对于类型bool,正确地表明值v 尚未在映射中。见Spec: Index expressions

对于map type M

...如果映射为nil 或不包含此类条目,则a[x]zero value 的值类型M

【讨论】:

  • 非常感谢您的指导、反馈和修改。就像我说的,我是 Go 新手。再次感谢!
【解决方案2】:

我认为您可以进行map 的访问。 像这样的

visited := make(map[visit]Boolean)

你可以设置visited的值。

visited[visit]=true

最后,您可以通过此代码获取所有访问过的位置

for k, _ := range visited {
    unique = append(unique, k)
}

【讨论】:

    【解决方案3】:

    我想你可以借助 Map 来解决这个难题

    https://play.golang.org/p/b7JtHYQ3N8

    package main
    
    import (
        "fmt"
    )
    
    type visit struct {
        x, y int
    }
    
    func main() {
        var visited []visit
        var unique []visit
    
        uniqueMap := map[visit]int{}
    
        visited = append(visited, visit{1, 100})
        visited = append(visited, visit{2, 2})
        visited = append(visited, visit{1, 100})
        visited = append(visited, visit{1, 1})
    
        for _, v := range visited {
            if _, exist := uniqueMap[v]; !exist {
                uniqueMap[v] = 1
                unique = append(unique, v)
            } else {
                uniqueMap[v]++
            }
        }
        fmt.Printf("Uniques: %v\nMaps:%v\n", unique, uniqueMap)
    }
    

    【讨论】:

      猜你喜欢
      • 2012-11-10
      • 1970-01-01
      • 2016-02-24
      • 1970-01-01
      • 2018-08-03
      • 2014-02-09
      • 1970-01-01
      • 2015-12-08
      相关资源
      最近更新 更多