Mostafa telah menunjukkan bahwa metode seperti itu sepele untuk ditulis, dan mkb memberi Anda petunjuk untuk menggunakan pencarian biner dari paket sortir. Tetapi jika Anda akan melakukan banyak pemeriksaan seperti itu, Anda mungkin juga mempertimbangkan untuk menggunakan peta.
Itu sepele untuk memeriksa apakah kunci peta tertentu ada dengan menggunakan value, ok := yourmap[key]idiom. Karena Anda tidak tertarik dengan nilai, Anda mungkin juga membuat map[string]struct{}contoh. Menggunakan kosong di struct{}sini memiliki keuntungan karena tidak memerlukan ruang tambahan dan tipe peta internal Go dioptimalkan untuk nilai-nilai semacam itu. Karena itu, map[string] struct{}merupakan pilihan populer untuk set di dunia Go.
Perhatikan juga, bahwa Anda harus menulis struct{}{}untuk mendapatkan nilai struct kosong sehingga Anda dapat meneruskannya ke peta saat Anda ingin menambahkan elemen. Coba saja, dan jika Anda menemukan masalah, jangan ragu untuk bertanya. Anda juga dapat menggunakan solusi Mostafa jika itu lebih mudah bagi Anda untuk memahami (kecuali jika Anda memiliki data dalam jumlah besar).
tux21b
5
Solusi itu sederhana, itu benar. Tetapi apa yang diperlukan untuk menambahkan fungsi dasar seperti itu ke dalam runtime? Saya belum menemukan masalah seperti itu di Go repo on github. Itu menyedihkan dan aneh.
Igor Petrov
1
Bagaimana cara map[string] boolmembandingkan dengan map[string] struct{}. map[string] struct{}sepertinya hack terutama menginisialisasi struct kosongstruct {}{}
vadasambar
@IgorPetrov setuju, saya terkejut fitur dasar seperti itu belum ada di runtime.
jcollum
180
Tidak, metode seperti itu tidak ada, tetapi sepele untuk ditulis:
func contains(s []int, e int)bool{for _, a := range s {if a == e {returntrue}}returnfalse}
Anda dapat menggunakan peta jika pencarian itu merupakan bagian penting dari kode Anda, tetapi peta juga memiliki biaya.
Sebenarnya ini tidak sepele, karena Anda harus menulis satu untuk setiap jenis yang Anda gunakan, dan karena tidak ada overloading, Anda harus memberi nama setiap fungsi secara berbeda, seperti dalam C. append () dapat bekerja secara umum karena memiliki dukungan runtime khusus. Isi generik akan berguna untuk alasan yang sama, tetapi sebenarnya solusi generik hanyalah dukungan generik dalam bahasa tersebut.
Eloff
15
@ Eloffinterface{}
Alex Lockwood
2
@Alex Lockwood apakah ini benar-benar berfungsi dengan antarmuka?
Ory Band
101
trivial == 7 baris kode termasuk 1 loop 1 cabang jika pernyataan dan 1 perbandingan? Saya pikir saya kehilangan sesuatu di sini ...
tothemario
3
Tapi mengapa tidak menambahkan ini sendiri?
Luna Lovegood
16
Jika slice diurutkan, ada pencarian biner diimplementasikan dalam satu sortpaket .
Alih-alih menggunakan slice,map mungkin solusi yang lebih baik.
contoh sederhana:
package main
import"fmt"
func contains(slice []string, item string)bool{set:= make(map[string]struct{}, len(slice))for _, s := range slice {set[s]=struct{}{}}
_, ok :=set[item]return ok
}
func main(){
s :=[]string{"a","b"}
s1 :="a"
fmt.Println(contains(s, s1))}
Dalam bentuknya yang sekarang, kode ini tidak menawarkan manfaat, karena tidak ada gunanya membuat peta dari sebuah slice jika Anda hanya akan menggunakannya sekali. - Agar bermanfaat, kode ini sebaiknya menyediakan fungsi sliceToMapyang melakukan semua persiapan. Setelah itu, menanyakan peta itu sepele dan efisien.
Roland Illig
9
The semacam paket menyediakan blok bangunan jika slice Anda disortir atau Anda bersedia untuk mengatasinya.
SearchStringberjanji untuk kembali the index to insert x if x is not present (it could be len(a)), jadi cek yang mengungkapkan apakah string berisi slice yang diurutkan.
Dalam hal waktu, pencarian reguler adalah O(n)dan solusi ini membuatnya O(n*log(n)).
plesiv
@plesiv ini pencarian biner, AFAICS. Bukankah itu membuatnya O (log n)?
Henrik Aasted Sørensen
ya, biner-pencarian dan fungsi containsyang O(log(n)), tapi pendekatan secara keseluruhan O(n*log(n))karena semacam itu.
plesiv
3
Anda bisa menggunakan paket refleksi untuk beralih di atas antarmuka yang tipe konkretnya adalah slice:
func HasElem(s interface{}, elem interface{})bool{
arrV := reflect.ValueOf(s)if arrV.Kind()== reflect.Slice{for i :=0; i < arrV.Len(); i++{// XXX - panics if slice element points to an unexported struct field// see https://golang.org/pkg/reflect/#Value.Interfaceif arrV.Index(i).Interface()== elem {returntrue}}}returnfalse}
Tentu Anda dapat menggunakan paket refleksi tetapi hanya karena Anda bisa, tidak berarti Anda harus melakukannya. Refleksi sangat mahal.
Justin Ohms
3
Jika tidak layak menggunakan peta untuk menemukan item berdasarkan kunci, Anda dapat mempertimbangkan alat yang mematikan . Goderive menghasilkan implementasi khusus tipe berisi metode, membuat kode Anda mudah dibaca dan efisien.
Contoh;
type Foostruct{Field1stringField2int}
func Test(m Foo)bool{var allItems []Fooreturn deriveContainsFoo(allItems, m)}
Untuk menghasilkan metode deriveContainsFoo:
Instal goderive dengan go get -u github.com/awalterschulze/goderive
Jalankan goderive ./...di folder ruang kerja Anda
Metode ini akan dihasilkan untuk deriveContains:
func deriveContainsFoo(list []Foo, item Foo)bool{for _, v := range list {if v == item {returntrue}}returnfalse}
Goderive memiliki dukungan untuk beberapa metode penolong bermanfaat lainnya untuk menerapkan gaya pemrograman fungsional.
Tidak yakin obat generik diperlukan di sini. Anda hanya perlu kontrak untuk perilaku yang Anda inginkan. Melakukan hal berikut tidak lebih dari apa yang harus Anda lakukan dalam bahasa lain jika Anda ingin objek Anda sendiri berperilaku dalam koleksi, dengan menimpa Equals () dan GetHashCode () misalnya.
type Identifiableinterface{GetIdentity()string}
func IsIdentical(thisIdentifiable, that Identifiable)bool{return(&this==&that)||(this.GetIdentity()== that.GetIdentity())}
func contains(s []Identifiable, e Identifiable)bool{for _, a := range s {ifIsIdentical(a,e){returntrue}}returnfalse}
"tidak lebih dari apa yang harus Anda lakukan dalam bahasa lain" tidak benar - misalnya dalam C # Contains()diimplementasikan List<T>, jadi Anda hanya perlu menerapkan Equals()untuk pekerjaan itu.
George
1
Saya membuat tolok ukur yang sangat sederhana dengan solusi dari jawaban ini.
Saya memikirkannya tetapi tidak terlalu representatif karena mesin saya tidak begitu kuat.
F. Norbert
0
Mungkin dianggap sedikit 'retas' tetapi tergantung pada ukuran dan isi slice, Anda dapat menggabungkan slice bersama-sama dan melakukan pencarian string.
Misalnya Anda memiliki slice yang berisi nilai kata tunggal (mis. "Ya", "tidak", "mungkin"). Hasil ini ditambahkan ke irisan. Jika Anda ingin memeriksa apakah irisan ini berisi hasil "mungkin", Anda dapat menggunakan
exSlice :=["yes","no","yes","maybe"]if strings.Contains(strings.Join(exSlice,","),"maybe"){
fmt.Println("We have a maybe!")}
Seberapa cocok ini benar-benar tergantung pada ukuran irisan dan panjang anggotanya. Mungkin ada masalah kinerja atau kesesuaian untuk irisan besar atau nilai panjang, tetapi untuk irisan kecil ukuran terbatas dan nilai sederhana itu adalah satu-liner yang valid untuk mencapai hasil yang diinginkan.
Tidak akan berfungsi untuk situasi di mana elemen memiliki teks yang mirip tetapi tidak persis samaexSlice := ["yes and no", "maybe", "maybe another"]
Raees Iqbal
Ini adalah pendekatan yang agak bagus untuk mencapai solusi one-liner cepat dan kotor. Anda hanya perlu membutuhkan pembatas yang tidak ambigu (bisa berupa koma) dan melakukan pekerjaan ekstra untuk mengurung kedua string ","+strings.Join(exSlice,",")+","",maybe,"
:,
-1
Gaya bepergian:
func Contains(n int, match func(i int)bool)bool{for i :=0; i < n; i++{if match(i){returntrue}}returnfalse}
s :=[]string{"a","b","c","o"}// test if s contains "o"
ok :=Contains(len(s), func(i int)bool{return s[i]=="o"})
Jawaban:
Mostafa telah menunjukkan bahwa metode seperti itu sepele untuk ditulis, dan mkb memberi Anda petunjuk untuk menggunakan pencarian biner dari paket sortir. Tetapi jika Anda akan melakukan banyak pemeriksaan seperti itu, Anda mungkin juga mempertimbangkan untuk menggunakan peta.
Itu sepele untuk memeriksa apakah kunci peta tertentu ada dengan menggunakan
value, ok := yourmap[key]
idiom. Karena Anda tidak tertarik dengan nilai, Anda mungkin juga membuatmap[string]struct{}
contoh. Menggunakan kosong distruct{}
sini memiliki keuntungan karena tidak memerlukan ruang tambahan dan tipe peta internal Go dioptimalkan untuk nilai-nilai semacam itu. Karena itu,map[string] struct{}
merupakan pilihan populer untuk set di dunia Go.sumber
struct{}{}
untuk mendapatkan nilai struct kosong sehingga Anda dapat meneruskannya ke peta saat Anda ingin menambahkan elemen. Coba saja, dan jika Anda menemukan masalah, jangan ragu untuk bertanya. Anda juga dapat menggunakan solusi Mostafa jika itu lebih mudah bagi Anda untuk memahami (kecuali jika Anda memiliki data dalam jumlah besar).map[string] bool
membandingkan denganmap[string] struct{}
.map[string] struct{}
sepertinya hack terutama menginisialisasi struct kosongstruct {}{}
Tidak, metode seperti itu tidak ada, tetapi sepele untuk ditulis:
Anda dapat menggunakan peta jika pencarian itu merupakan bagian penting dari kode Anda, tetapi peta juga memiliki biaya.
sumber
interface{}
Jika slice diurutkan, ada pencarian biner diimplementasikan dalam satu
sort
paket .sumber
Alih-alih menggunakan
slice
,map
mungkin solusi yang lebih baik.contoh sederhana:
http://play.golang.org/p/CEG6cu4JTf
sumber
sliceToMap
yang melakukan semua persiapan. Setelah itu, menanyakan peta itu sepele dan efisien.The semacam paket menyediakan blok bangunan jika slice Anda disortir atau Anda bersedia untuk mengatasinya.
SearchString
berjanji untuk kembalithe index to insert x if x is not present (it could be len(a))
, jadi cek yang mengungkapkan apakah string berisi slice yang diurutkan.sumber
O(n)
dan solusi ini membuatnyaO(n*log(n))
.contains
yangO(log(n))
, tapi pendekatan secara keseluruhanO(n*log(n))
karena semacam itu.Anda bisa menggunakan paket refleksi untuk beralih di atas antarmuka yang tipe konkretnya adalah slice:
https://play.golang.org/p/jL5UD7yCNq
sumber
Jika tidak layak menggunakan peta untuk menemukan item berdasarkan kunci, Anda dapat mempertimbangkan alat yang mematikan . Goderive menghasilkan implementasi khusus tipe berisi metode, membuat kode Anda mudah dibaca dan efisien.
Contoh;
Untuk menghasilkan metode deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
di folder ruang kerja AndaMetode ini akan dihasilkan untuk deriveContains:
Goderive memiliki dukungan untuk beberapa metode penolong bermanfaat lainnya untuk menerapkan gaya pemrograman fungsional.
sumber
sumber
Tidak yakin obat generik diperlukan di sini. Anda hanya perlu kontrak untuk perilaku yang Anda inginkan. Melakukan hal berikut tidak lebih dari apa yang harus Anda lakukan dalam bahasa lain jika Anda ingin objek Anda sendiri berperilaku dalam koleksi, dengan menimpa Equals () dan GetHashCode () misalnya.
sumber
Contains()
diimplementasikanList<T>
, jadi Anda hanya perlu menerapkanEquals()
untuk pekerjaan itu.Saya membuat tolok ukur yang sangat sederhana dengan solusi dari jawaban ini.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
Ini bukan tolok ukur yang nyata karena pada awalnya, saya belum memasukkan terlalu banyak elemen tetapi merasa ragu untuk memotong dan mengubahnya.
sumber
Mungkin dianggap sedikit 'retas' tetapi tergantung pada ukuran dan isi slice, Anda dapat menggabungkan slice bersama-sama dan melakukan pencarian string.
Misalnya Anda memiliki slice yang berisi nilai kata tunggal (mis. "Ya", "tidak", "mungkin"). Hasil ini ditambahkan ke irisan. Jika Anda ingin memeriksa apakah irisan ini berisi hasil "mungkin", Anda dapat menggunakan
Seberapa cocok ini benar-benar tergantung pada ukuran irisan dan panjang anggotanya. Mungkin ada masalah kinerja atau kesesuaian untuk irisan besar atau nilai panjang, tetapi untuk irisan kecil ukuran terbatas dan nilai sederhana itu adalah satu-liner yang valid untuk mencapai hasil yang diinginkan.
sumber
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
Gaya bepergian:
sumber