在Go Slice或Array中查找唯一项目 [英] Finding Unique Items in a Go Slice or Array

查看:177
本文介绍了在Go Slice或Array中查找唯一项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很新,现在我真的很困惑。

假设我有一个坐标列表,并且可以说我在这个坐标列表中有一些双打。我不能为我的生活弄清楚如何制作一个独特的列表。通常在Python中,我可以用集合和其他内置函数欺骗。

 包主

导入(
fmt
反映


类型访问struct {
x,y int
}

func main(){
var visited []访问
var unique []访问

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(独特的访问{1,1})

fmt.Println(唯一)

//通过访问并找到独特元素
for _,v :=访问的范围{
for _,u:=范围唯一{

fmt.Printf(这是唯一:%v \ n,唯一)
fmt.Printf (比较%v到%v是%v \ n,v,u,reflect.DeepEqual(v,u))

if reflect.DeepEqual(v,u){
fmt.Println(跳过)
} else {
u nique = append(unique,v)
}
}
}

fmt.Println(unique)
}

运行它在游乐场

解决方案

代码中有多个错误。最严重的是,因为您将访问过的切片的每个特定元素与所有元素唯一,如果 unique 包含至少一个不同的字符,您将最终追加它。接下来,如果独特中的元素多于您的内部),您将最终多次追加它>循环不打破。这不是你想要的,你想添加 none 元素。。



还要注意,如果Go的 struct 是可比的,如果它的每个字段是可比较的。由于您的访问结构仅包含2个 int 字段,因此它是可比较的,所以您可以比较使用 = 运算符访问类型,不需要那么丑陋 reflect.DeepEqual()。请参阅规格:比较运算符


如果所有字段都具有可比性,则结构值可比。如果其相应的非空白字段相同,则两个结构值相等。


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

 <$ c $访问{1,100},
访问{2,2},
访问{1,100},
访问{1, 1},
}
var unique []拜访

for _,v:=拜访范围{
skip:= false
for _,u :=范围独特{
如果v == u {
skip = true
break
}
}
if!skip {
unique =附加(唯一,v)
}
}

fmt.Println(唯一)

输出(在去游乐场试试):

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



另类



这是真的Go没有内置集合类型,但可以轻松地将 map [visit] bool 作为集合。这样,它变得非常简单!请注意,访问可用作地图中的关键字,因为它具有可比性(参见上文)。

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

for _,v:=访问范围{
unique [ v] = true
}

fmt.Println(unique)

输出(在去游乐场试试):

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

唯一的列表是地图中的键列表。



如果您想独特访问值作为切片,请参阅此变体:

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

for _,v:=访问范围{
if!m [v] {
m [v ] = true
unique = append(unique,v)
}
}

fmt.Println (unique)

输出(如预期的那样,在

  [{play.golang.org/p/A6l6DW6LM1rel =nofollow> Go Playground ):

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

请注意,此索引表达式:<$ c如果 v 已经在地图中,$ c> m [v] 的计算结果为 true (作为关键字, true 是我们存储在地图中的值)。如果 v 尚未在映射中,则 m [v] 将产生值类型的零值, code>> > 尚未在地图中显示。请参阅规范:索引表达式


对于地图类型 M

...如果地图是 nil 或者不包含这样的条目, a [x] 零值对于 M



的值类型

I'm pretty new to go and I'm really, really confused right now.

Let's say I have a list of coordinates and lets say I have some doubles in this list of coordinates. I can't for the life of me figure out how to make a unique list. Normally in Python I can "cheat" with sets and other built-ins. Not so much in 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

解决方案

There are multiple errors in your code. The most serious is that since you're comparing each specific element of the visited slice to all of the elements of unique, you will end up appending it if unique contains at least one which is different. And going forward, you will end up appending it multiple times if there are more elements in unique which differ as your inner for loop doesn't "break". This is not what you want, you want to append elements which equals to none of unique.

Also note that a struct in Go is comparable if each of its fields are comparable. Since your visit struct contains only 2 int fields, it is comparable and so you can compare values of visit types simply with the = operator, no need that ugly reflect.DeepEqual(). See Spec: Comparison operators:

Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.

Here's a simplified, correct version that applies your logic:

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)

Output (try it on the Go Playground):

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

Alternative

It's true that Go doesn't have a built-in set type, but you can use a map[visit]bool easily as a set. With that, it becomes really simple! Note that visit can be used as key in the map because it is comparable (see above).

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)

Output (try it on the Go Playground):

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

The unique "list" is the list of keys in the map.

If you want the unique visit values as a slice, see this variant:

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

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

fmt.Println(unique)

Output (as expected, try it on the Go Playground):

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

Note that this index expression: m[v] evaluates to true if v is already in the map (as a key, true is the value we stored in the map). If v is not yet in the map, m[v] yields the zero value of the value type which is false for the type bool, properly telling that the value v is not yet in the map. See Spec: Index expressions:

For a of map type M:

...if the map is nil or does not contain such an entry, a[x] is the zero value for the value type of M

这篇关于在Go Slice或Array中查找唯一项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆