Go语言 如何检查for循环中的唯一性?

t3psigkw  于 2023-02-17  发布在  Go
关注(0)|答案(5)|浏览(145)

是否有方法检查切片/Map是否存在值?
我想将一个值添加到切片中如果它*存在于切片中。
这是可行的,但似乎冗长。有更好的方法来做到这一点吗?

orgSlice := []int{1, 2, 3}
newSlice := []int{}
newInt := 2
    
newSlice = append(newSlice, newInt)
for _, v := range orgSlice {
    if v != newInt {
        newSlice = append(newSlice, v)
    }
}

newSlice == [2 1 3]
8i9zcol2

8i9zcol21#

你的方法每次插入都需要线性时间,更好的方法是使用map[int]struct{},或者,你也可以使用map[int]bool或类似的函数,但是空的struct{}有一个优点,它不占用任何额外的空间,因此map[int]struct{}是整数集的常用选择。

示例:

set := make(map[int]struct{})
set[1] = struct{}{}
set[2] = struct{}{}
set[1] = struct{}{}
// ...

for key := range(set) {
  fmt.Println(key)
}
// each value will be printed only once, in no particular order

// you can use the ,ok idiom to check for existing keys
if _, ok := set[1]; ok {
  fmt.Println("element found")
} else {
  fmt.Println("element not found")
}
8gsdolmq

8gsdolmq2#

最有效的方法可能是遍历切片,如果找不到切片就追加。

func AppendIfMissing(slice []int, i int) []int {
    for _, ele := range slice {
        if ele == i {
            return slice
        }
    }
    return append(slice, i)
}

它简单明了,对于小列表来说速度很快。
而且,它总是比当前基于Map的解决方案更快,无论如何,基于Map的解决方案都会在整个切片上迭代;这个解决方案在发现新值已经存在时立即返回。2两个解决方案都在迭代时比较元素。3(每个map赋值语句肯定在内部至少做一个map键比较。4)只有当你能在多次插入中维护它时,map才有用。5如果你在每次插入时都重建它,那么所有的优点都失去了。
如果您确实需要有效地处理大型列表,请考虑按排序顺序维护列表。(我怀疑排序顺序对您来说并不重要,因为您的第一个解决方案附加在列表的开头,而您的最新解决方案附加在末尾。)如果您始终保持列表排序,则可以使用sort.search函数来执行有效的二进制插入。

ndasle7k

ndasle7k3#

另一种选择:

package main
import "golang.org/x/tools/container/intsets"

func main() {
   var (
      a intsets.Sparse
      b bool
   )
   b = a.Insert(9)
   println(b) // true
   b = a.Insert(9)
   println(b) // false
}

https://pkg.go.dev/golang.org/x/tools/container/intsets

3duebb1j

3duebb1j4#

如果缺失数字的数目未知,则使用此选项

AppendIfMissing := func(sl []int, n ...int) []int {
        cache := make(map[int]int)
        for _, elem := range sl {
            cache[elem] = elem
        }
        for _, elem := range n {
            if _, ok := cache[elem]; !ok {
                sl = append(sl, elem)
            }
        }
        return sl
    }
e5njpo68

e5njpo685#

区分结构体的数组:

func distinctObjects(objs []ObjectType) (distinctedObjs [] ObjectType){
        var output []ObjectType
    for i:= range objs{
        if output==nil || len(output)==0{
            output=append(output,objs[i])
        } else {
            founded:=false
            for j:= range output{
                    if output[j].fieldname1==objs[i].fieldname1 && output[j].fieldname2==objs[i].fieldname2 &&......... {
                    founded=true
                }
            }
            if !founded{
                output=append(output,objs[i])
            }
        }
    }
    return output
}

这里的结构体类似于:

type ObjectType struct {
    fieldname1 string
    fieldname2 string
    .........
}

对象将通过此处选中的字段区分:

if output[j].fieldname1==objs[i].fieldname1 && output[j].fieldname2==objs[i].fieldname2 &&......... {

相关问题