답변:
Mostafa는 이미 그러한 방법을 작성하는 것이 쉽지 않다고 지적했으며 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{}
를 사용하는 대신 더 나은 솔루션 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
return을 약속 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 도구를 고려할 수 있습니다 . Goderive는 contains 메소드의 유형별 구현을 생성하여 코드를 읽기 쉽고 효율적으로 만듭니다.
예;
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
처음에는 너무 많은 요소를 삽입하지 않았지만 자유롭게 포크하고 변경할 수 있기 때문에 실제 벤치 마크가 아닙니다.
약간 '해키'로 간주 될 수 있지만 슬라이스의 크기와 내용에 따라 슬라이스를 결합하고 문자열 검색을 수행 할 수 있습니다.
예를 들어 단일 단어 값을 포함하는 슬라이스가 있습니다 (예 : "yes", "no", "maybe"). 이 결과는 슬라이스에 추가됩니다. 이 슬라이스에 "아마도"결과가 포함되어 있는지 확인하려면
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"
})