Відповіді:
Мостафа вже вказував, що такий метод є тривіальним для написання, і 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
пакеті .
Замість використання A 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))
обумовлений родом.
Ви можете використовувати пакет відображення для ітерації інтерфейсу, конкретним типом якого є фрагмент:
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 створює специфічну для конкретного типу реалізацію методу містить, що робить ваш код читабельним та ефективним.
Приклад;
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"
})