슬라이스 방법이 들어 있습니다


답변:


226

Mostafa는 이미 그러한 방법을 작성하는 것이 쉽지 않다고 지적했으며 mkb는 정렬 패키지에서 이진 검색을 사용하는 힌트를 제공했습니다. 그러나 이러한 포함 검사를 많이 수행하려는 경우 맵을 대신 사용할 수도 있습니다.

value, ok := yourmap[key]관용구 를 사용하여 특정 맵 키가 있는지 확인하는 것은 쉽지 않습니다 . 값에 관심이 없으므로 map[string]struct{}예를 들어 만들 수도 있습니다 . struct{}여기 에 빈 공간을 사용하면 추가 공간이 필요하지 않으며 Go의 내부지도 유형이 해당 종류의 값에 최적화되어 있다는 이점이 있습니다. 따라서 map[string] struct{}Go 세계에서 인기있는 세트입니다.


27
또한 struct{}{}빈 구조체의 값을 가져 와서 요소를 추가 할 때 맵에 전달할 수 있도록 작성해야합니다. 시도해보고 문제가 발생하면 언제든지 문의하십시오. 대량의 데이터가없는 한 이해하기 쉬운 경우 Mostafa의 솔루션을 사용할 수도 있습니다.
tux21b

5
해결책은 간단합니다. 그러나 이러한 기본 기능을 런타임에 추가하려면 무엇이 필요합니까? github의 Go repo에서 그러한 문제를 찾지 못했습니다. 슬프고 이상합니다.
Igor Petrov

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 {
            return true
        }
    }
    return false
}

조회가 코드의 중요한 부분 인 경우 맵을 사용할 수 있지만 맵에 비용이 많이 듭니다.


257
실제로 사용하는 각 유형마다 하나씩 작성해야하고 오버로드가 없으므로 C와 같이 각 함수의 이름을 다르게 지정해야합니다. append ()는 특수한 런타임 지원 기능이 있기 때문에 일반적으로 작동 할 수 있습니다. 제네릭 포함은 같은 이유로 유용하지만 실제로 제네릭 솔루션은 언어에서 제네릭 지원입니다.
Eloff

15
@Eloffinterface{}
Alex Lockwood

2
@Alex Lockwood 이것이 실제로 인터페이스에서 작동합니까?
Ory Band

101
사소한 = 1 루프 1 분기 if 문과 1 비교를 포함하여 7 줄의 코드? 여기에 뭔가 빠진 것 같습니다 ...
tothemario

3
그러나 왜 이것들을 핵심 자체에 추가하지 않습니까?
Luna Lovegood


11

를 사용하는 대신 더 나은 솔루션 slicemap수 있습니다.

간단한 예 :

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))

}

http://play.golang.org/p/CEG6cu4JTf


34
현재 코드에서는이 코드를 한 번만 사용하려는 경우 슬라이스에서 맵을 구성 할 필요가 없으므로 이점이 없습니다. — 유용하게이 코드 sliceToMap는 모든 준비 작업을 수행 하는 기능 을 제공해야합니다 . 그 후, 맵 쿼리는 간단하고 효율적입니다.
Roland Illig

9

정렬 당신의 조각이 정렬 또는 당신이 그것을 분류하고자하는 경우, 패키지는 빌딩 블록을 제공한다.

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
}

SearchStringreturn을 약속 the index to insert x if x is not present (it could be len(a))하므로 문자열을 검사하면 정렬 된 슬라이스가 포함되어 있는지 확인할 수 있습니다.


시간의 관점에서, 정규 검색은 O(n)이 솔루션으로 이루어집니다 O(n*log(n)).
plesiv

@plesiv 이진 검색 AFAICS입니다. 그것이 O (log n)가되지 않습니까?
Henrik Aasted Sørensen

예, 이진 검색과 함수 containsO(log(n))이지만 전체 접근 방식은 O(n*log(n))정렬에 의한 것입니다.
plesiv

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.Interface
            if arrV.Index(i).Interface() == elem {
                return true
            }
        }
    }

    return false
}

https://play.golang.org/p/jL5UD7yCNq


3
물론 reflect 패키지를 사용할 수 있지만 그렇게 할 수 있다고해서 꼭 그렇게해야하는 것은 아닙니다. 반사는 매우 비싸다.
저스틴 옴스 1

3

키를 기반으로 항목을 찾기 위해 맵을 사용할 수없는 경우 goderive 도구를 고려할 수 있습니다 . Goderive는 contains 메소드의 유형별 구현을 생성하여 코드를 읽기 쉽고 효율적으로 만듭니다.

예;

type Foo struct {
    Field1 string
    Field2 int
} 

func Test(m Foo) bool {
     var allItems []Foo
     return deriveContainsFoo(allItems, m)
}

deriveContainsFoo 메소드를 생성하려면 다음을 수행하십시오.

  • 함께 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는 함수형 프로그래밍 스타일을 적용 할 수있는 다른 유용한 도우미 메서드를 지원합니다.


2
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
}

2

여기에 제네릭이 필요한지 확실하지 않습니다. 원하는 행동에 대한 계약이 필요합니다. 예를 들어 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
}

1
"다른 언어로해야 할 것 이상은 아닙니다"는 사실이 아닙니다. 예를 들어 C # Contains()이 구현되어 List<T>있으므로 Equals()해당 작업 을 구현 하기 만하면됩니다.
조지

1

이 답변의 솔루션으로 매우 간단한 벤치 마크를 만들었습니다.

https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7

처음에는 너무 많은 요소를 삽입하지 않았지만 자유롭게 포크하고 변경할 수 있기 때문에 실제 벤치 마크가 아닙니다.


나는 그것에 대해 생각했지만 내 기계가 그렇게 강력하지 않기 때문에 그렇게 대표적이지는 않습니다.
F. Norbert

0

약간 '해키'로 간주 될 수 있지만 슬라이스의 크기와 내용에 따라 슬라이스를 결합하고 문자열 검색을 수행 할 수 있습니다.

예를 들어 단일 단어 값을 포함하는 슬라이스가 있습니다 (예 : "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"]
Raees Iqbal

이것은 빠르고 더러워진 1 라이너 솔루션을 달성하기위한 다소 좋은 접근 방법입니다. 명확한 구분 기호 (쉼표 일 수 있음)가 필요하고 두 문자열을 괄호로 묶는 추가 작업을 수행하면됩니다. ","+strings.Join(exSlice,",")+",",",maybe,"
nobar

-1

바둑 스타일 :

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"
})

2
이것은 질문에 대답하지 않으며 추가 정보를 제공하지 않습니다.
Croolman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.