มีอะไรที่คล้ายกับslice.contains(object)
วิธีการใน Go โดยไม่ต้องทำการค้นหาผ่านแต่ละองค์ประกอบเป็นชิ้นหรือไม่?
มีอะไรที่คล้ายกับslice.contains(object)
วิธีการใน Go โดยไม่ต้องทำการค้นหาผ่านแต่ละองค์ประกอบเป็นชิ้นหรือไม่?
คำตอบ:
Mostafa ได้ชี้ให้เห็นแล้วว่าวิธีการดังกล่าวเป็นเรื่องเล็กน้อยที่จะเขียนและ mkb ให้คำแนะนำให้คุณใช้การค้นหาแบบไบนารีจากแพคเกจการเรียงลำดับ แต่ถ้าคุณจะทำเช็คจำนวนมากเช่นนั้นคุณอาจลองใช้แผนที่แทน
มันสำคัญมากที่จะตรวจสอบว่ามีรหัสแผนที่เฉพาะอยู่หรือไม่โดยใช้value, ok := yourmap[key]
สำนวน เนื่องจากคุณไม่สนใจคุณค่าคุณอาจสร้างmap[string]struct{}
ตัวอย่างเช่น การใช้ที่ว่างเปล่าstruct{}
ที่นี่มีข้อได้เปรียบที่ไม่ต้องการพื้นที่เพิ่มเติมและประเภทแผนที่ภายในของ Go ได้รับการปรับให้เหมาะสมสำหรับค่าประเภทนั้น ดังนั้นจึงmap[string] struct{}
เป็นตัวเลือกยอดนิยมสำหรับชุดในโลก Go
struct{}{}
เพื่อรับค่าของโครงสร้างที่ว่างเปล่าเพื่อให้คุณสามารถส่งมันไปยังแผนที่ของคุณเมื่อคุณต้องการเพิ่มองค์ประกอบ ลองใช้และถ้าคุณประสบปัญหาใด ๆ อย่าลังเลที่จะถาม นอกจากนี้คุณยังสามารถใช้โซลูชัน Mostafa ถ้าคุณเข้าใจได้ง่ายขึ้น (เว้นแต่คุณจะมีข้อมูลจำนวนมาก)
map[string] bool
ดูเหมือนแฮ็คโดยเฉพาะอย่างยิ่งการเริ่มต้นโครงสร้างว่างmap[string] struct{}
map[string] struct{}
struct {}{}
ไม่ได้ไม่มีวิธีการดังกล่าว แต่เป็นเรื่องเล็กน้อยที่จะเขียน:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
คุณสามารถใช้แผนที่ได้หากการค้นหานั้นเป็นส่วนสำคัญของรหัสของคุณ แต่แผนที่ก็มีค่าใช้จ่ายด้วย
interface{}
หากชิ้นจะถูกจัดเรียงมีการค้นหาแบบไบนารีดำเนินการในแพคเกจsort
แทนการใช้slice
, map
อาจจะเป็นทางออกที่ดีกว่า
ตัวอย่างง่ายๆ:
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
ที่ใช้ในการเตรียมการทั้งหมด หลังจากนั้นการสืบค้นแผนที่นั้นเล็กน้อยและมีประสิทธิภาพ
เรียงแพคเกจให้การก่อสร้างตึกถ้าชิ้นของคุณจะถูกจัดเรียงหรือคุณยินดีที่จะจัดเรียง
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
สัญญาว่าจะส่งคืนthe index to insert x if x is not present (it could be len(a))
ดังนั้นการตรวจสอบของที่แสดงให้เห็นว่าสตริงที่มีการจัดเรียงชิ้น
O(n)
O(n*log(n))
contains
ต่างO(log(n))
ๆ แต่วิธีการโดยรวมนั้นO(n*log(n))
เกิดจากการเรียงลำดับ
คุณสามารถใช้แพคเกจreflectเพื่อวนซ้ำอินเทอร์เฟซที่มีชนิดคอนกรีตเป็นชิ้น:
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
}
ถ้ามันเป็นไปไม่ได้ที่จะใช้แผนที่เพื่อค้นหารายการที่ขึ้นอยู่กับคีย์คุณสามารถพิจารณาเครื่องมือgoderive Goderive สร้างการใช้งานเฉพาะของประเภท method ซึ่งทำให้โค้ดของคุณสามารถอ่านได้และมีประสิทธิภาพ
ตัวอย่าง;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
วิธีสร้างเมธอด deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
ในโฟลเดอร์เวิร์กสเปซของคุณวิธีนี้จะถูกสร้างขึ้นสำหรับ deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive มีการสนับสนุนวิธีการช่วยเหลือที่มีประโยชน์อื่น ๆ อีกมากมายที่จะใช้รูปแบบการเขียนโปรแกรมการทำงานในระหว่างการเดินทาง
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
}
ไม่แน่ใจว่าจำเป็นต้องใช้ยาชื่อสามัญที่นี่ คุณเพียงแค่ต้องทำสัญญาสำหรับพฤติกรรมที่คุณต้องการ การทำสิ่งต่อไปนี้ไม่ใช่แค่สิ่งที่คุณต้องทำในภาษาอื่น ๆ หากคุณต้องการให้วัตถุของคุณทำงานเป็นกลุ่มโดยการเอาชนะ Equals () และ GetHashCode ()
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()
มีการใช้งานList<T>
ดังนั้นคุณจะต้องนำไปใช้Equals()
กับงานนั้นเท่านั้น
ฉันสร้างเกณฑ์มาตรฐานง่าย ๆ ด้วยวิธีแก้ปัญหาจากคำตอบเหล่านี้
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
มันไม่ใช่มาตรฐานที่แท้จริงเพราะในตอนแรกฉันยังไม่ได้ใส่องค์ประกอบมากเกินไป แต่อย่าลังเลที่จะแยกและเปลี่ยนมัน
อาจถือว่าเป็น 'แฮ็ค' เล็กน้อย แต่ขึ้นอยู่กับขนาดและเนื้อหาของชิ้นคุณสามารถเข้าร่วมชิ้นด้วยกันและทำการค้นหาสตริง
ตัวอย่างเช่นคุณมีชิ้นที่มีค่าคำเดียว (เช่น "ใช่", "ไม่", "อาจจะ") ผลลัพธ์เหล่านี้ผนวกเข้ากับส่วน หากคุณต้องการตรวจสอบว่าส่วนนี้มีผลลัพธ์ "อาจจะ" คุณอาจใช้
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
วิธีที่เหมาะสมนี้ขึ้นอยู่กับขนาดของส่วนและความยาวของสมาชิก อาจมีปัญหาเรื่องประสิทธิภาพหรือความเหมาะสมสำหรับชิ้นขนาดใหญ่หรือค่าความยาว แต่สำหรับชิ้นเล็ก ๆ ที่มีขนาด จำกัด และค่าอย่างง่ายมันเป็นหนึ่งซับที่ถูกต้องเพื่อให้ได้ผลลัพธ์ที่ต้องการ
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
และ",maybe,"
สไตล์ไป:
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"
})