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.
Observe também que é necessário escrever 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).
tux21b
5
A solução é simples, é verdade. Mas o que é preciso para adicionar essa funcionalidade básica ao tempo de execução? Não encontrei esses problemas no repositório Go no github. Isso é triste e estranho.
Igor Petrov
1
Como se map[string] boolcompara com map[string] struct{}. map[string] struct{}parece ser um hack especialmente inicializar um struct vaziostruct {}{}
vadasambar
@IgorPetrov concordou, estou surpreso que um recurso tão básico ainda não esteja no tempo de execução.
jcollum 21/04
180
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 {returntrue}}returnfalse}
Você pode usar um mapa se essa pesquisa for uma parte importante do seu código, mas os mapas também custam.
Na verdade, isso não é trivial, porque você precisa escrever um para cada tipo que usa e como não há sobrecarga, é necessário nomear cada função de maneira diferente, como em C. append () pode funcionar genericamente porque possui suporte especial ao tempo de execução. Um conteúdo genérico seria útil pelo mesmo motivo, mas realmente a solução genérica é apenas o suporte a genéricos no idioma.
Eloff
15
@Eloffinterface{}
Alex Lockwood
2
@ Alex Lockwood isso realmente funcionará com interfaces?
Ory Banda
101
trivial == 7 linhas de código incluindo 1 loop 1 ramificação if declaração e 1 comparação? Eu acho que estou faltando alguma coisa aqui ...
tothemario
3
Mas por que não adicioná-los no próprio núcleo?
Luna Lovegood
16
Se a fatia é ordenada, há uma busca binária implementado no sortpacote .
Em vez de usar a slice, mappode 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))}
Na sua forma atual, esse código não oferece nenhum benefício, pois não faz sentido construir um mapa a partir de uma fatia se você o usar apenas uma vez. - Para ser útil, esse código deve fornecer uma função sliceToMapque faça toda a preparação. Depois disso, consultar o mapa é trivial e eficiente.
Roland Illig 26/10/2015
9
O pacote de classificação fornece os blocos de construção se sua fatia é classificada ou você deseja classificá-la.
SearchStringpromete 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.
Em termos de tempo, a pesquisa regular é O(n)e esta solução o faz O(n*log(n)).
plesiv
@plesiv é uma pesquisa binária, AFAICS. Isso não tornaria O (log n)?
Henrik Aasted Sørensen
sim, a pesquisa binária e a função containssão O(log(n)), mas a abordagem geral se O(n*log(n))deve ao tipo.
plesiv
3
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.Interfaceif arrV.Index(i).Interface()== elem {returntrue}}}returnfalse}
Claro que você pode usar o pacote de reflexão, mas apenas porque você pode, não significa que você deveria. A reflexão é muito cara.
Justin Ohms
3
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 Foostruct{Field1stringField2int}
func Test(m Foo)bool{var allItems []Fooreturn deriveContainsFoo(allItems, m)}
Para gerar o método deriveContainsFoo:
Instale o goderive com go get -u github.com/awalterschulze/goderive
Executar goderive ./...na pasta da área de trabalho
Este método será gerado para deriveContains:
func deriveContainsFoo(list []Foo, item Foo)bool{for _, v := range list {if v == item {returntrue}}returnfalse}
O Goderive tem suporte para alguns outros métodos auxiliares úteis para aplicar um estilo de programação funcional em movimento.
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 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}
"não é mais do que o que você teria que fazer em outros idiomas" não é realmente verdade - por exemplo, o C # Contains()é implementado List<T>, então você só precisa implementar Equals()esse trabalho.
George
1
Criei uma referência muito simples com as soluções dessas respostas.
Pensei nisso, mas não é tão representativo devido ao fato de minha máquina não ser tão poderosa.
F. Norbert
0
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.
Não funcionará para situações em que elementos tenham texto semelhante, mas não exatamente o mesmoexSlice := ["yes and no", "maybe", "maybe another"]
Raees Iqbal
Essa é uma abordagem bastante agradável para obter uma solução de uma linha rápida e suja. Você só precisa exigir um delimitador inequívoco (pode ser uma vírgula) e fazer o trabalho extra para ","+strings.Join(exSlice,",")+","",maybe,"
agrupar as
-1
O estilo 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"})
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 vaziostruct{}
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.fonte
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 commap[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:
Você pode usar um mapa se essa pesquisa for uma parte importante do seu código, mas os mapas também custam.
fonte
interface{}
Se a fatia é ordenada, há uma busca binária implementado no
sort
pacote .fonte
Em vez de usar a
slice
,map
pode ser uma solução melhor.exemplo simples:
http://play.golang.org/p/CEG6cu4JTf
fonte
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.
SearchString
promete retornarthe 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.fonte
O(n)
e esta solução o fazO(n*log(n))
.contains
sãoO(log(n))
, mas a abordagem geral seO(n*log(n))
deve ao tipo.Você pode usar o pacote reflect para iterar sobre uma interface cujo tipo concreto é uma fatia:
https://play.golang.org/p/jL5UD7yCNq
fonte
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;
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:
O Goderive tem suporte para alguns outros métodos auxiliares úteis para aplicar um estilo de programação funcional em movimento.
fonte
fonte
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.
fonte
Contains()
é implementadoList<T>
, então você só precisa implementarEquals()
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.
fonte
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
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.
fonte
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
O estilo go:
fonte