Мостафа уже указал, что такой метод написать тривиально, и mkb подсказал вам использовать двоичный поиск из пакета sort. Но если вы собираетесь делать много таких проверок, вы можете использовать карту.
С помощью этой value, ok := yourmap[key]идиомы легко проверить, существует ли определенный ключ карты . Поскольку вас не интересует значение, вы можете также создать, map[string]struct{}например. Использование struct{}здесь пустого имеет то преимущество, что оно не требует дополнительного пространства, а внутренний тип карты Go оптимизирован для таких значений. Таким образом, map[string] struct{}это популярный выбор для наборов в мире Go.
Также обратите внимание, что вы должны написать, struct{}{}чтобы получить значение пустой структуры, чтобы вы могли передать ее на карту, когда вы хотите добавить элемент. Просто попробуйте, и если у вас возникнут какие-либо проблемы, не стесняйтесь спрашивать. Вы также можете использовать решение Mostafa, если вам легче его понять (если у вас нет огромных объемов данных).
tux21b
5
Решение простое, это правда. Но что нужно, чтобы добавить такую базовую функциональность во время выполнения? Я не нашел таких проблем в репо Go на github. Это грустно и странно.
Игорь Петров
1
Как map[string] boolсравнить с map[string] struct{}. map[string] struct{}кажется хаком, особенно инициализация пустой структурыstruct {}{}
vadasambar
@IgorPetrov согласился, я удивлен, что такая базовая функция еще не во время выполнения.
Jcollum
180
Нет, такого метода не существует, но написать тривиально:
func contains(s []int, e int)bool{for _, a := range s {if a == e {returntrue}}returnfalse}
Вы можете использовать карту, если этот поиск является важной частью вашего кода, но карты тоже стоят.
На самом деле это не тривиально, потому что вы должны написать по одному для каждого типа, который вы используете, и поскольку нет перегрузки, вы должны называть каждую функцию по-разному, как в C. Универсальное содержимое будет полезно по той же причине, но на самом деле универсальное решение - это просто поддержка обобщений в языке.
Eloff
15
@Eloffinterface{}
Алекс Локвуд
2
@ Алекс Локвуд будет ли это работать с интерфейсами?
Ory Band
101
тривиально == 7 строк кода, включая 1 цикл, 1 ветвь оператора if и 1 сравнение? Я думаю, что я что-то здесь
упускаю
3
Но почему бы не добавить их в само ядро?
Луна Лавгуд
16
Если срез отсортирован, есть бинарный поиск осуществляется в в 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которая делает всю подготовку. После этого запросы к карте тривиальны и эффективны.
Роланд Иллиг
9
Пакет сортировки предоставляет строительные блоки, если ваш фрагмент отсортирован или вы хотите его отсортировать.
SearchStringобещает вернуть the index to insert x if x is not present (it could be len(a)), так что проверка показывает, содержит ли строка отсортированный фрагмент.
С точки зрения времени, регулярный поиск есть, O(n)и это решение делает его O(n*log(n)).
Плесив
@plesiv это бинарный поиск, AFAICS. Разве это не сделало бы это O (log n)?
Хенрик Аастед Серенсен
да, бинарный поиск и функция containsесть O(log(n)), но общий подход O(n*log(n))обусловлен сортировкой.
Плесив
3
Вы можете использовать отражающий пакет для перебора интерфейса, конкретным типом которого является срез:
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}
Конечно, вы можете использовать пакет отражения, но только потому, что вы можете, не значит, что вы должны. Отражение очень дорогое.
Джастин
3
Если использовать карту для поиска элементов по ключу нецелесообразно , вы можете воспользоваться инструментом goderive . Goderive генерирует специфическую для типа реализацию метода contains, делая ваш код читабельным и эффективным.
Пример;
type Foostruct{Field1stringField2int}
func Test(m Foo)bool{var allItems []Fooreturn deriveContainsFoo(allItems, m)}
Чтобы сгенерировать метод diverveContainsFoo:
Установите Goderive с go get -u github.com/awalterschulze/goderive
Запустите goderive ./...в вашей папке рабочего пространства
Этот метод будет сгенерирован для DeriveContains:
func deriveContainsFoo(list []Foo, item Foo)bool{for _, v := range list {if v == item {returntrue}}returnfalse}
Goderive поддерживает довольно много других полезных вспомогательных методов для применения функционального стиля программирования в go.
Не уверен, что здесь нужны дженерики. Вам просто нужен контракт для вашего желаемого поведения. Выполнение следующего не более чем то, что вы должны были бы сделать на других языках, если бы вы хотели, чтобы ваши собственные объекты вели себя в коллекциях, переопределяя, например, Equals () и GetHashCode ().
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}
«не больше, чем то, что вы должны были бы делать на других языках», на самом деле не так - например, в C # Contains()реализован List<T>, так что вам нужно всего лишь реализовать его Equals()для этой работы.
Джордж,
1
Я создал очень простой тест с решениями из этих ответов.
Я думал об этом, но он не такой представительный, потому что моя машина не такая мощная.
Ф. Норберт
-1
Стиль Go:
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"})
Это не отвечает на вопрос и не дает дополнительную информацию.
Croolman
-1
Это может считаться немного «хакерским», но в зависимости от размера и содержимого фрагмента вы можете объединить фрагмент и выполнить поиск по строке.
Например, у вас есть фрагмент, содержащий значения одного слова (например, «да», «нет», «возможно»). Эти результаты добавляются к срезу. Если вы хотите проверить, содержит ли этот срез какие-либо «возможно» результаты, вы можете использовать
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"]
Raees Iqbal
Это довольно хороший подход для достижения быстрого и грязного однострочного решения. Вам просто нужно указать однозначный разделитель (может быть запятой) и выполнить дополнительную работу, чтобы заключить в скобки обе строки:, ","+strings.Join(exSlice,",")+","и",maybe,"
Ответы:
Мостафа уже указал, что такой метод написать тривиально, и mkb подсказал вам использовать двоичный поиск из пакета sort. Но если вы собираетесь делать много таких проверок, вы можете использовать карту.
С помощью этой
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 {}{}
Нет, такого метода не существует, но написать тривиально:
Вы можете использовать карту, если этот поиск является важной частью вашего кода, но карты тоже стоят.
источник
interface{}
Если срез отсортирован, есть бинарный поиск осуществляется в в
sort
пакете .источник
Вместо того чтобы использовать
slice
,map
может быть лучшим решением.простой пример:
http://play.golang.org/p/CEG6cu4JTf
источник
sliceToMap
которая делает всю подготовку. После этого запросы к карте тривиальны и эффективны.Пакет сортировки предоставляет строительные блоки, если ваш фрагмент отсортирован или вы хотите его отсортировать.
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))
обусловлен сортировкой.Вы можете использовать отражающий пакет для перебора интерфейса, конкретным типом которого является срез:
https://play.golang.org/p/jL5UD7yCNq
источник
Если использовать карту для поиска элементов по ключу нецелесообразно , вы можете воспользоваться инструментом goderive . Goderive генерирует специфическую для типа реализацию метода contains, делая ваш код читабельным и эффективным.
Пример;
Чтобы сгенерировать метод diverveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
в вашей папке рабочего пространстваЭтот метод будет сгенерирован для DeriveContains:
Goderive поддерживает довольно много других полезных вспомогательных методов для применения функционального стиля программирования в go.
источник
источник
Не уверен, что здесь нужны дженерики. Вам просто нужен контракт для вашего желаемого поведения. Выполнение следующего не более чем то, что вы должны были бы сделать на других языках, если бы вы хотели, чтобы ваши собственные объекты вели себя в коллекциях, переопределяя, например, Equals () и GetHashCode ().
источник
Contains()
реализованList<T>
, так что вам нужно всего лишь реализовать егоEquals()
для этой работы.Я создал очень простой тест с решениями из этих ответов.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
Это не настоящий эталон, потому что изначально я не вставил слишком много элементов, но не стесняюсь раскошелиться и изменить его.
источник
Стиль Go:
источник
Это может считаться немного «хакерским», но в зависимости от размера и содержимого фрагмента вы можете объединить фрагмент и выполнить поиск по строке.
Например, у вас есть фрагмент, содержащий значения одного слова (например, «да», «нет», «возможно»). Эти результаты добавляются к срезу. Если вы хотите проверить, содержит ли этот срез какие-либо «возможно» результаты, вы можете использовать
Насколько это действительно подходит, зависит от размера среза и длины его элементов. Могут быть проблемы производительности или пригодности для больших срезов или длинных значений, но для меньших срезов конечного размера и простых значений это допустимая однострочная строка для достижения желаемого результата.
источник
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
и",maybe,"