当前位置:  开发笔记 > 编程语言 > 正文

在Go Slice或Array中查找唯一项

如何解决《在GoSlice或Array中查找唯一项》经验,为你挑选了1个好方法。

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

假设我有一个坐标列表,让我说这个坐标列表中有一些双打.我不能为我的生活弄清楚如何制作一个独特的清单.通常在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



1> icza..:

您的代码中存在多个错误.最严重的是,由于您将visited切片的每个特定元素与所有元素进行比较unique,如果unique包含至少一个不同的元素,您最终会附加它.如果有更多的元素unique因为你的内部for循环没有"中断" 而有所不同,那么你最后会多次附加它.这是不是你想要的,你要追加相等于元素没有unique.

另请注意,struct如果Go中的每个字段都具有可比性,则可以比较.由于您的visit结构只包含2个int字段,因此它具有可比性,因此您可以visit简单地将类型的值与=运算符进行比较,而不需要那么难看reflect.DeepEqual().请参阅规范:比较运算符:

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

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

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}]

请注意,此索引表达式:m[v]计算trueif v是否已经在地图中(作为键,true是我们存储在地图中的值).如果v尚未在地图中,则为该类型m[v]生成值类型的零值,正确地告知该值尚未在地图中.请参阅规范:索引表达式:falseboolv

对于地图类型 M:

...如果地图是nil或不包含这样的条目,a[x]则值类型为零值M

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有