IT TIP

이동 : 고유 한 경우 추가

itqueen 2020. 12. 29. 08:12
반응형

이동 : 고유 한 경우 추가


값이 있는지 슬라이스 / 맵을 확인하는 방법이 있습니까?

슬라이스에 존재 하지 않는 경우 에만 슬라이스에 값을 추가하고 싶습니다 .

이것은 작동하지만 장황 해 보입니다. 이를 수행하는 더 나은 방법이 있습니까?

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]

귀하의 접근 방식은 각 삽입에 대해 선형 시간이 걸립니다. 더 나은 방법은 map[int]struct{}. 또는 a 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")
}

가장 효율적인 방법은 슬라이스를 반복하고 찾을 수없는 경우 추가하는 것입니다.

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

간단하고 명확하며 작은 목록의 경우 빠릅니다.

또한 현재지도 기반 솔루션보다 항상 더 빠릅니다. 맵 기반 솔루션은 무엇이든지간에 전체 슬라이스를 반복합니다. 이 솔루션은 새 값이 이미 있음을 발견하면 즉시 반환됩니다. 두 솔루션 모두 반복되는 요소를 비교합니다. (각 맵 할당 문은 확실히 내부적으로 적어도 하나의 맵 키 비교를 수행합니다.) 맵은 여러 삽입에 걸쳐 유지할 수있는 경우에만 유용합니다. 삽입 할 때마다 재건하면 모든 이점이 손실됩니다.

큰 목록을 효율적으로 처리해야하는 경우 목록을 정렬 된 순서로 유지하는 것이 좋습니다. (첫 번째 솔루션이 목록의 시작 부분에 추가되고 최신 솔루션이 마지막에 추가되기 때문에 순서가 중요하지 않은 것 같습니다.) 목록을 항상 정렬 상태로 유지하면 sort.Search 기능을 사용하여 다음을 수행 할 수 있습니다. 효율적인 이진 삽입을 수행하십시오.


구조체의 배열 구별 :

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

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()
}

참조 URL : https://stackoverflow.com/questions/9251234/go-append-if-unique

반응형