Есть ли что-то похожее на метод slice.contains(object)
в Go без необходимости выполнять поиск через каждый элемент в срезе?
Содержит метод для среза
Ответ 1
Mostafa уже указала, что такой метод тривиально писать, а mkb дал вам подсказку использовать двоичный поиск из пакета сортировки. Но если вы собираетесь делать много таких проверок, вы можете также рассмотреть возможность использования карты.
Тривиально проверить, существует ли конкретный ключ карты, используя идиому value, ok := yourmap[key]
. Поскольку вы не заинтересованы в значении, вы также можете создать map[string]struct{}
, например. Использование пустого struct{}
здесь имеет то преимущество, что оно не требует дополнительного пространства, а тип внутреннего типа Go оптимизирован для таких значений. Поэтому map[string] struct{}
является популярным выбором для множеств в мире Go.
Ответ 2
Нет, такой метод не существует, но тривиально писать:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Вы можете использовать карту, если этот поиск является важной частью вашего кода, но карты также имеют стоимость.
Ответ 3
Если срез отсортирован, существует двоичный поиск, реализованный в пакете sort
.
Ответ 4
Вместо использования 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))
}
Ответ 5
Вы можете использовать пакет отражения для итерации по интерфейсу, конкретный тип которого представляет собой срез:
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
}
Ответ 6
Не уверен, что здесь нужны дженерики. Вам просто нужен контракт для желаемого поведения. Выполнение следующих действий не более чем то, что вы должны делать на других языках, если бы вы хотели, чтобы ваши собственные объекты вели себя в коллекциях, переопределяя, например, 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
}
Ответ 7
Если использовать карту для поиска элементов по ключу нецелесообразно, вы можете воспользоваться инструментом goderive. Goderive генерирует реализацию метода для конкретного типа, которая делает ваш код читабельным и эффективным.
Пример;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return 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 {
return true
}
}
return false
}
Goderive поддерживает несколько других полезных вспомогательных методов для применения функционального стиля программирования в go.
Ответ 8
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
}
Ответ 9
Пакет sort предоставляет строительные блоки, если ваш фрагмент отсортирован или вы хотите его отсортировать.
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))
, поэтому проверка показывает, содержит ли строка отсортированный фрагмент.