doudan1123 2015-12-05 22:06
浏览 232
已采纳

在Go Slice或数组中查找唯一项

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
", unique)
            fmt.Printf("Comparing %v to %v is %v
", v, u, reflect.DeepEqual(v, u))

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

    fmt.Println(unique)
}

<kbd>Run it on Playground</kbd>

  • 写回答

3条回答 默认 最新

  • dpwjx32578146 2015-12-05 22:18
    关注

    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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 对于这个问题的解释说明
  • ¥200 询问:python实现大地主题正反算的程序设计,有偿
  • ¥15 smptlib使用465端口发送邮件失败
  • ¥200 总是报错,能帮助用python实现程序实现高斯正反算吗?有偿
  • ¥15 对于squad数据集的基于bert模型的微调
  • ¥15 为什么我运行这个网络会出现以下报错?CRNN神经网络
  • ¥20 steam下载游戏占用内存
  • ¥15 CST保存项目时失败
  • ¥20 java在应用程序里获取不到扬声器设备
  • ¥15 echarts动画效果的问题,请帮我添加一个动画。不要机器人回答。