Go: Append if unique

后端 未结 4 1602
深忆病人
深忆病人 2021-01-30 06:28

Is there a way to check slices/maps for the presence of a value?

I would like to add a value to a slice only if it does not

相关标签:
4条回答
  • 2021-01-30 06:45

    distincting a array of a struct :

    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
    }
    

    where the struct here is something like :

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

    the object will distinct by checked fields here :

    if output[j].fieldname1==objs[i].fieldname1 && output[j].fieldname2==objs[i].fieldname2 &&......... {
    
    0 讨论(0)
  • 2021-01-30 06:53

    Most efficient is likely to be iterating over the slice and appending if you don't find it.

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

    It's simple and obvious and will be fast for small lists.

    Further, it will always be faster than your current map-based solution. The map-based solution iterates over the whole slice no matter what; this solution returns immediately when it finds that the new value is already present. Both solutions compare elements as they iterate. (Each map assignment statement certainly does at least one map key comparison internally.) A map would only be useful if you could maintain it across many insertions. If you rebuild it on every insertion, then all advantage is lost.

    If you truly need to efficiently handle large lists, consider maintaining the lists in sorted order. (I suspect the order doesn't matter to you because your first solution appended at the beginning of the list and your latest solution appends at the end.) If you always keep the lists sorted then you you can use the sort.Search function to do efficient binary insertions.

    0 讨论(0)
  • 2021-01-30 06:55
    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()
    }
    
    0 讨论(0)
  • 2021-01-30 06:58

    Your approach would take linear time for each insertion. A better way would be to use a map[int]struct{}. Alternatively, you could also use a map[int]bool or something similar, but the empty struct{} has the advantage that it doesn't occupy any additional space. Therefore map[int]struct{} is a popular choice for a set of integers.

    Example:

    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")
    }
    
    0 讨论(0)
提交回复
热议问题