Respostas:
Mostafa já apontou que esse método é trivial de escrever, e o mkb deu uma dica para você usar a pesquisa binária no pacote de classificação. Mas se você fizer muitas dessas verificações, também poderá usar um mapa.
É trivial verificar se existe uma chave de mapa específica usando o value, ok := yourmap[key]
idioma. Como você não está interessado no valor, você também pode criar um, map[string]struct{}
por exemplo. Usar um vazio struct{}
aqui tem a vantagem de não exigir espaço adicional e o tipo de mapa interno do Go é otimizado para esse tipo de valores. Portanto, map[string] struct{}
é uma escolha popular para os sets no mundo Go.
struct{}{}
para obter o valor da estrutura vazia, para que você possa passá-lo ao seu mapa quando desejar adicionar um elemento. Apenas tente e, se encontrar algum problema, não hesite em perguntar. Você também pode usar a solução da Mostafa se for mais fácil para você entender (a menos que você tenha grandes quantidades de dados).
map[string] bool
compara com map[string] struct{}
. map[string] struct{}
parece ser um hack especialmente inicializar um struct vaziostruct {}{}
Não, esse método não existe, mas é trivial escrever:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Você pode usar um mapa se essa pesquisa for uma parte importante do seu código, mas os mapas também custam.
interface{}
Se a fatia é ordenada, há uma busca binária implementado no sort
pacote .
Em vez de usar a slice
, map
pode ser uma solução melhor.
exemplo simples:
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
que faça toda a preparação. Depois disso, consultar o mapa é trivial e eficiente.
O pacote de classificação fornece os blocos de construção se sua fatia é classificada ou você deseja classificá-la.
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
promete retornar the index to insert x if x is not present (it could be len(a))
, portanto, uma verificação disso revela se a string está contida na fatia classificada.
O(n)
e esta solução o faz O(n*log(n))
.
contains
são O(log(n))
, mas a abordagem geral se O(n*log(n))
deve ao tipo.
Você pode usar o pacote reflect para iterar sobre uma interface cujo tipo concreto é uma fatia:
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
}
Se não for possível usar um mapa para encontrar itens com base em uma chave, considere a ferramenta goderive . O Goderive gera uma implementação específica de tipo de um método contains, tornando seu código legível e eficiente.
Exemplo;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
Para gerar o método deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
na pasta da área de trabalhoEste método será gerado para deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
O Goderive tem suporte para alguns outros métodos auxiliares úteis para aplicar um estilo de programação funcional em movimento.
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
}
Não tenho certeza se os genéricos são necessários aqui. Você só precisa de um contrato para o comportamento desejado. Fazer o seguinte não é mais do que seria necessário em outros idiomas se você desejasse que seus próprios objetos se comportassem em coleções, substituindo Equals () e GetHashCode () por exemplo.
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()
é implementado List<T>
, então você só precisa implementar Equals()
esse trabalho.
Criei uma referência muito simples com as soluções dessas respostas.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
Não é uma referência real, porque, inicialmente, não inseri muitos elementos, mas sinto-me à vontade para alterá-lo.
Pode ser considerado um pouco "hacky", mas dependendo do tamanho e do conteúdo da fatia, você pode unir a fatia e fazer uma pesquisa de string.
Por exemplo, você tem uma fatia contendo valores de palavra única (por exemplo, "sim", "não", "talvez"). Esses resultados são anexados a uma fatia. Se você quiser verificar se esta fatia contém algum resultado "talvez", use
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
A adequação disso realmente depende do tamanho da fatia e do comprimento de seus membros. Pode haver problemas de desempenho ou adequação para fatias grandes ou valores longos, mas para fatias menores de tamanho finito e valores simples, é uma linha única válida para alcançar o resultado desejado.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
O estilo go:
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"
})