Câu trả lời:
Mostafa đã chỉ ra rằng một phương pháp như vậy là tầm thường để viết và mkb đã cho bạn một gợi ý để sử dụng tìm kiếm nhị phân từ gói sắp xếp. Nhưng nếu bạn định làm nhiều kiểm tra như vậy, bạn cũng có thể cân nhắc sử dụng bản đồ thay thế.
Việc kiểm tra xem một khóa bản đồ cụ thể có tồn tại hay không bằng cách sử dụng value, ok := yourmap[key]
thành ngữ này. Vì bạn không quan tâm đến giá trị, bạn cũng có thể tạo một map[string]struct{}
ví dụ. Sử dụng một khoảng trống struct{}
ở đây có lợi thế là nó không yêu cầu bất kỳ không gian bổ sung nào và loại bản đồ nội bộ của Go được tối ưu hóa cho loại giá trị đó. Do đó, map[string] struct{}
là một lựa chọn phổ biến cho các bộ trong thế giới Go.
struct{}{}
để lấy giá trị của cấu trúc trống để bạn có thể chuyển nó vào bản đồ của mình khi bạn muốn thêm một phần tử. Chỉ cần thử nó, và nếu bạn gặp bất kỳ vấn đề, hãy hỏi. Bạn cũng có thể sử dụng giải pháp của Mostafa nếu bạn dễ hiểu hơn (trừ khi bạn có lượng dữ liệu khổng lồ).
map[string] bool
so sánh với map[string] struct{}
. map[string] struct{}
có vẻ như một vụ hack đặc biệt là khởi tạo một cấu trúc trốngstruct {}{}
Không, phương pháp như vậy không tồn tại, nhưng không quan trọng để viết:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Bạn có thể sử dụng bản đồ nếu việc tra cứu đó là một phần quan trọng trong mã của bạn, nhưng bản đồ cũng có chi phí.
interface{}
Nếu lát được sắp xếp, có một tìm kiếm nhị phân được thực hiện trong các sort
gói .
Thay vì sử dụng một slice
, map
có thể là một giải pháp tốt hơn.
ví dụ đơn giản:
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
thực hiện tất cả các bước chuẩn bị. Sau đó, truy vấn bản đồ là chuyện nhỏ và hiệu quả.
Các loại gói cung cấp các khối xây dựng nếu lát của bạn là sắp xếp hoặc bạn sẵn sàng để sắp xếp nó.
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
hứa sẽ quay trở lại the index to insert x if x is not present (it could be len(a))
, vì vậy kiểm tra xem có cho biết chuỗi có chứa lát cắt đã sắp xếp hay không.
O(n)
và giải pháp này làm cho nó O(n*log(n))
.
contains
là O(log(n))
, nhưng cách tiếp cận tổng thể là O(n*log(n))
do sắp xếp.
Bạn có thể sử dụng gói phản chiếu để lặp lại trên một giao diện có loại cụ thể là một lát:
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
}
Nếu việc sử dụng bản đồ để tìm vật phẩm dựa trên khóa là không khả thi, bạn có thể xem xét việc đỡ đầu công cụ. Goderive tạo ra một kiểu triển khai cụ thể của phương thức chứa, làm cho mã của bạn vừa dễ đọc vừa hiệu quả.
Thí dụ;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
Để tạo phương thức deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
trong thư mục không gian làm việc của bạnPhương thức này sẽ được tạo cho deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive đã hỗ trợ khá nhiều phương thức trợ giúp hữu ích khác để áp dụng phong cách lập trình chức năng.
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
}
Không chắc chắn thuốc generic là cần thiết ở đây. Bạn chỉ cần một hợp đồng cho hành vi mong muốn của bạn. Thực hiện các thao tác sau không nhiều hơn những gì bạn sẽ phải làm trong các ngôn ngữ khác nếu bạn muốn các đối tượng của mình tự hành xử trong các bộ sưu tập, bằng cách ghi đè Equals () và GetHashCode () chẳng hạn.
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()
được triển khai List<T>
, vì vậy bạn chỉ phải thực hiện Equals()
cho công việc đó.
Tôi đã tạo ra một điểm chuẩn rất đơn giản với các giải pháp từ những câu trả lời này.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
Đó không phải là một điểm chuẩn thực sự bởi vì ban đầu, tôi đã không chèn quá nhiều yếu tố nhưng cảm thấy thoải mái khi rẽ nhánh và thay đổi nó.
Nó có thể được coi là một chút 'hacky' nhưng tùy thuộc vào kích thước và nội dung của lát cắt, bạn có thể tham gia lát cắt với nhau và thực hiện tìm kiếm chuỗi.
Ví dụ: bạn có một lát chứa các giá trị từ đơn (ví dụ: "có", "không", "có thể"). Những kết quả này được nối vào một lát. Nếu bạn muốn kiểm tra xem lát này có chứa bất kỳ kết quả "có thể" nào không, bạn có thể sử dụng
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
Làm thế nào phù hợp điều này thực sự phụ thuộc vào kích thước của lát và chiều dài của các thành viên của nó. Có thể có các vấn đề về hiệu suất hoặc sự phù hợp cho các lát lớn hoặc giá trị dài, nhưng đối với các lát nhỏ hơn có kích thước hữu hạn và các giá trị đơn giản thì đó là một lớp lót hợp lệ để đạt được kết quả mong muốn.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
và",maybe,"
Phong cách đi:
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"
})