Go:附加,如果唯一

时间:2012-02-12 18:05:56

标签: append go slice

有没有办法检查切片/贴图是否存在值?

如果切片中存在 ,我想为切片 添加一个值。

这有效,但似乎很冗长。有没有更好的方法来做到这一点?

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]

5 个答案:

答案 0 :(得分:74)

每次插入时,您的方法都需要线性时间。更好的方法是使用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")
}

答案 1 :(得分:30)

最高效的可能是在切片上迭代,如果找不到则附加。

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

它简单明了,对于小型列表来说速度很快。

此外,它总是比您当前基于地图的解决方案更快。无论如何,基于地图的解决方案遍历整个切片;当此解决方案发现新值已存在时立即返回。两种解决方案都会在迭代时比较元素。 (每个地图赋值语句当然在内部至少进行一次地图键比较。)只有在可以跨多次插入维护地图时,地图才有用。如果您在每次插入时重建它,那么所有优势都将丢失。

如果您确实需要有效处理大型列表,请考虑按排序顺序维护列表。 (我怀疑顺序对你没关系,因为你的第一个解决方案附加在列表的开头,最后的解决方案附加在最后。)如果你始终保持列表排序,那么你可以使用sort.Search函数来做有效的二进制插入。

答案 2 :(得分:1)

另一种选择:

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

答案 3 :(得分:0)

区分结构数组:

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 &&......... {

答案 4 :(得分:0)

package main

import (
    "fmt"
    "os"
    "reflect"
)

func main() {
/*  s := []string{"a", "b"}
    fmt.Println(s)

    s = AppendIfMissing(s, "4").([]string)

    fmt.Println(s)*/

/*  var a []*string
    a = make([]*string, 0)
    e := "4"
    a = AppendIfMissing(a, &e).([]*string)
    fmt.Println(*a[0])*/

    var a []*float64
    a = make([]*float64, 3)
    e := 4.4
    d := 4.41
    a = AppendIfMissing(a, &e).([]*float64)
    a = AppendIfMissing(a, &d).([]*float64)
    fmt.Println(*a[3], *a[4])
}

func AppendIfMissing(array interface{}, element interface{}) interface{} {
    if reflect.ValueOf(array).IsNil() {
        fmt.Fprintf(os.Stderr, "array not initialized\n")
        return nil
    }

    switch reflect.TypeOf(array).Kind() {
    case reflect.Slice:
        arrayV := reflect.ValueOf(array)
        arrayVLen := arrayV.Len()
        if arrayVLen == 0 {//if make len == 0
            sliceNew := reflect.MakeSlice(reflect.ValueOf(array).Type(), 1, 1)
            if sliceNew.Index(0).Type() != reflect.ValueOf(element).Type() {
                fmt.Fprintf(os.Stderr, "types are not same\n")
                return sliceNew.Interface()
            }

            sliceNew.Index(0).Set(reflect.ValueOf(element))
            return sliceNew.Interface()
        }
        for i := 0; i < arrayVLen; i++ {
            if i == 0 && reflect.ValueOf(element).Kind() != arrayV.Index(i).Kind() {
                fmt.Fprintf(os.Stderr, "types are not same\n")
                return array
            }
            if arrayV.Index(i).Interface() == element {
                return array
            }
        }
    default:
        fmt.Fprintf(os.Stderr, "first element is not array\n")
        return array
    }

    arrayV := reflect.ValueOf(array)
    elementV := reflect.ValueOf(element)
    appendAE := reflect.Append(arrayV, elementV)

    return appendAE.Interface()
}