이동 : 고유 한 경우 추가
값이 있는지 슬라이스 / 맵을 확인하는 방법이 있습니까?
슬라이스에 존재 하지 않는 경우 에만 슬라이스에 값을 추가하고 싶습니다 .
이것은 작동하지만 장황 해 보입니다. 이를 수행하는 더 나은 방법이 있습니까?
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
'IT TIP' 카테고리의 다른 글
지원 저항 알고리즘-기술 분석 (0) | 2020.12.29 |
---|---|
Express.js에서 SSL / https를 강제하는 방법 (0) | 2020.12.29 |
xcode 단위 테스트에서 파일로드 (0) | 2020.12.29 |
Babel.js로 Async Await 제안을 트랜스 파일 하시겠습니까? (0) | 2020.12.29 |
PEP8 – sys.path를 사용하여 파일 맨 위에 가져 오지 않음 (0) | 2020.12.29 |