値の存在についてスライス/マップをチェックする方法はありますか?
スライスに値を追加したいonlynotはスライスに存在します。
これは機能しますが、冗長に見えます。これを行うためのより良い方法はありますか?
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{}
を使用することです。または、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)
}
シンプルで明白であり、小さなリストの場合は高速です。
さらに、現在のマップベースのソリューションよりも常に高速です。マップベースのソリューションは、スライスが何であれ反復します。このソリューションは、新しい値が既に存在することを検出するとすぐに戻ります。両方のソリューションは、要素を繰り返しながら比較します。 (各マップ割り当てステートメントは、少なくとも1つのマップキー比較を内部で確実に実行します。)マップは、多くの挿入にわたって維持できる場合にのみ有用です。挿入ごとに再構築すると、すべての利点が失われます。
大きなリストを本当に効率的に処理する必要がある場合は、リストをソート順に維持することを検討してください。 (リストの先頭に最初のソリューションが追加され、最後に最新のソリューションが追加されるため、順序は重要ではないと思われます。)リストを常にソートしたままにしておく場合、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()
}