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 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.
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 dengan map[string] struct{}
. map[string] struct{}
sepertinya hack terutama menginisialisasi struct kosongstruct {}{}
Tidak, metode seperti itu tidak ada, tetapi sepele untuk ditulis:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Anda dapat menggunakan peta jika pencarian itu merupakan bagian penting dari kode Anda, tetapi peta juga memiliki biaya.
interface{}
Jika slice diurutkan, ada pencarian biner diimplementasikan dalam satu sort
paket .
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))
}
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.
input := []string{"bird", "apple", "ocean", "fork", "anchor"}
sort.Strings(input)
fmt.Println(contains(input, "apple")) // true
fmt.Println(contains(input, "grow")) // false
...
func contains(s []string, searchterm string) bool {
i := sort.SearchStrings(s, searchterm)
return i < len(s) && s[i] == searchterm
}
SearchString
berjanji 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.
O(n)
dan solusi ini membuatnya O(n*log(n))
.
contains
yang O(log(n))
, tapi pendekatan secara keseluruhan O(n*log(n))
karena semacam itu.
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.Interface
if arrV.Index(i).Interface() == elem {
return true
}
}
}
return false
}
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 Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
Untuk menghasilkan metode deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
di folder ruang kerja AndaMetode ini akan dihasilkan untuk deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive memiliki dukungan untuk beberapa metode penolong bermanfaat lainnya untuk menerapkan gaya pemrograman fungsional.
func Contain(target interface{}, list interface{}) (bool, int) {
if reflect.TypeOf(list).Kind() == reflect.Slice || reflect.TypeOf(list).Kind() == reflect.Array {
listvalue := reflect.ValueOf(list)
for i := 0; i < listvalue.Len(); i++ {
if target == listvalue.Index(i).Interface() {
return true, i
}
}
}
if reflect.TypeOf(target).Kind() == reflect.String && reflect.TypeOf(list).Kind() == reflect.String {
return strings.Contains(list.(string), target.(string)), strings.Index(list.(string), target.(string))
}
return false, -1
}
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 Identifiable interface{
GetIdentity() string
}
func IsIdentical(this Identifiable, that Identifiable) bool{
return (&this == &that) || (this.GetIdentity() == that.GetIdentity())
}
func contains(s []Identifiable, e Identifiable) bool {
for _, a := range s {
if IsIdentical(a,e) {
return true
}
}
return false
}
Contains()
diimplementasikan List<T>
, jadi Anda hanya perlu menerapkan Equals()
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.
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.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
Gaya bepergian:
func Contains(n int, match func(i int) bool) bool {
for i := 0; i < n; i++ {
if match(i) {
return true
}
}
return false
}
s := []string{"a", "b", "c", "o"}
// test if s contains "o"
ok := Contains(len(s), func(i int) bool {
return s[i] == "o"
})