Go에“if x in”구성이 Python과 비슷합니까?


289

전체 배열을 반복 하지 않고x Go를 사용하여 배열에서 어떻게 확인할 수 있습니까? 언어에는 구문이 있습니까?

파이썬처럼 : if "x" in array: ...



7
AFAIK, 이에 대한 속기는 없습니다. 내부적으로 파이썬은 배열을 반복하므로 주변을 돌아 다니지 않습니다.
Danish94

6
BTW,이에 중요한 참고가 있다는 것입니다 방법입니다 (당신이 요청으로) "이 작업을 수행하는 [w] ithout 반복하는 전체 배열을 통해". 이러한 루프를 명시 적으로 (또는와 같은 함수 뒤에 strings.Index) 만들면 코드가 수행하는 작업을보다 명확하게 할 수 있습니다. 아마도 파이썬 in array:이 빠르고 마술 같은 일을하고 있다고 생각 합니다. AFAIK가 아닙니다. 루프를 명시 적으로 만들면 작성자 (및 모든 독자)가 다른 구현 (예 :지도)을 인식하고 고려할 수 있습니다.
Dave C

5
그러나 세트의 "x"가 실제로 매우 빠르면.
Roberto Alsina 2016 년

6
나는 (... 아직도 도착하지 않은 경우), 우리가 간결한 하나를 요구하고 우리가 프로그래밍 방식으로 빠른 접근을 요구하고 생각하지 않는다
Migwell

답변:


340

Go에는 내장 연산자가 없습니다. 배열을 반복해야합니다. 다음과 같이 자신의 함수를 작성할 수 있습니다.

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

전체 목록을 반복하지 않고 멤버십을 확인하려면 다음과 같이 배열 또는 슬라이스 대신 맵을 사용해야합니다.

visitedURL := map[string]bool {
    "http://www.google.com": true,
    "https://paypal.com": true,
}
if visitedURL[thisSite] {
    fmt.Println("Already been here.")
}

4
유형을 지정하지 않고이를 수행 할 수있는 방법이 있습니까? 모든 단일 유형에 대해 별도의 방법없이 일반적인 needleInHaystack (needle, haystack) 함수를 원한다고 가정 해 봅시다
Allen

25
리플렉션 패키지를 사용하여 수행 할 수는 있지만 상당히 비효율적입니다 (아마도 파이썬과 같은 동적 언어로 작성한 것처럼 느리게 나타납니다). 그 외에는 요 Go에 제네릭이 없다고 말하는 사람들의 의미입니다.
andybalholm

2
이 답변을 우연히 발견 한 사람은 맵을 정렬 할 수 없습니다. 이동 맵 사용의 큰 단점.
RisingSun

4
Javascript에서도 맵 (객체)을 정렬 할 수 없습니다. 개체가 알파벳순으로 값을 반환 하는 v8 버그 입니다.
kumarharsh

7
지도는 대부분의 언어로 정렬되어 있지 않습니다. 즉,지도 데이터 구조 (해시 맵)에 필적합니다.
Hejazzman

100

목록에 정적 값이 포함 된 경우 다른 솔루션입니다.

예 : 유효한 값 목록에서 유효한 값 확인 :

func IsValidCategory(category string) bool {
    switch category {
    case
        "auto",
        "news",
        "sport",
        "music":
        return true
    }
    return false
}

11
"유효한 값"이 데이터베이스에서 나온다면 어떻게해야합니까?
Rami Dabain

예, 이것은 깔끔하지만 이러한 값을 미리 정의 할 수있는 경우에만 가능합니다.
piggybox

2
@RonanDejhero 그러면 WHERE : myValue IN (하위 쿼리)를 사용할 수 있습니다 :)
anilech

3
이것은 최고의 답변에 비해 깔끔합니다
piggybox

50

이것은 "Goving Programming : 21 세기를위한 응용 프로그램 만들기"책에서 인용 한 것입니다.

이와 같이 간단한 선형 검색을 사용하는 것은 정렬되지 않은 데이터의 유일한 옵션이며 작은 조각 (최대 수백 개의 항목)에는 적합합니다. 그러나 더 큰 슬라이스, 특히 검색을 반복적으로 수행하는 경우 선형 검색은 매우 비효율적이며 평균적으로 매번 항목을 절반 씩 비교해야합니다.

Go는 이진 검색 알고리즘을 사용하는 sort.Search () 메소드를 제공합니다. 매번 log2 (n) 항목 (여기서 n은 항목 수) 만 비교해야합니다. 이러한 관점에서 볼 때 1000000 개의 항목을 선형 검색하려면 평균 500000 개의 비교가 필요하며 최악의 경우 1000000 개의 비교가 필요합니다. 이진 검색은 최악의 경우에도 최대 20 개의 비교가 필요합니다.

files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.Search(len(files),
    func(i int) bool { return files[i] >= target })
if i < len(files) && files[i] == target {
    fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}

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


10
검색을 반복하는 경우에만 의미가 있습니다. 그렇지 않으면 정렬 및 이진 검색의 경우 n * log (n) * log (n)이 복잡하고 선형 검색의 경우 n 만 복잡합니다.
Christian

1
n*log(n) + log(n)결과적으로 두 개의 독립적 인 작업이므로 실제로는 단지
pomo_mondreganto

27

sort를 사용하는 위의 예제는 비슷하지만 문자열의 경우 SearchString을 사용하십시오.

files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.SearchStrings(files, target)
if i < len(files) && files[i] == target {
    fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}

https://golang.org/pkg/sort/#SearchStrings


2
이 답변은이 답변 이전에 발생한 아래 답변의 정보가 적은 복사 붙여 넣기처럼 보입니다.
cytinus

@cytinus 무슨 대답을 하시겠습니까? 그것이 내가 본 유일한 것입니다 sort.SearchStrings.
akim

1
큰 조각을 통해 반복 검색 할 때 속도가 100 배 빨라졌습니다.
Xeoncross

20

방금 비슷한 질문이 있었고이 스레드의 제안 중 일부를 시도하기로 결정했습니다.

3 가지 유형의 조회에 대한 최상의 시나리오와 최악의 시나리오를 벤치마킹했습니다.

  • 지도 사용
  • 목록을 사용하여
  • switch 문 사용

함수 코드는 다음과 같습니다.

func belongsToMap(lookup string) bool {
list := map[string]bool{
    "900898296857": true,
    "900898302052": true,
    "900898296492": true,
    "900898296850": true,
    "900898296703": true,
    "900898296633": true,
    "900898296613": true,
    "900898296615": true,
    "900898296620": true,
    "900898296636": true,
}
if _, ok := list[lookup]; ok {
    return true
} else {
    return false
}
}


func belongsToList(lookup string) bool {
list := []string{
    "900898296857",
    "900898302052",
    "900898296492",
    "900898296850",
    "900898296703",
    "900898296633",
    "900898296613",
    "900898296615",
    "900898296620",
    "900898296636",
}
for _, val := range list {
    if val == lookup {
        return true
    }
}
return false
}

func belongsToSwitch(lookup string) bool {
switch lookup {
case
    "900898296857",
    "900898302052",
    "900898296492",
    "900898296850",
    "900898296703",
    "900898296633",
    "900898296613",
    "900898296615",
    "900898296620",
    "900898296636":
    return true
}
return false
}

최상의 시나리오는 목록에서 첫 번째 항목을 선택하고 최악의 경우 존재하지 않는 값을 사용합니다.

결과는 다음과 같습니다.

BenchmarkBelongsToMapWorstCase-4 2000000 787 ns/op BenchmarkBelongsToSwitchWorstCase-4 2000000000 0.35 ns/op BenchmarkBelongsToListWorstCase-4 100000000 14.7 ns/op BenchmarkBelongsToMapBestCase-4 2000000 683 ns/op BenchmarkBelongsToSwitchBestCase-4 100000000 10.6 ns/op BenchmarkBelongsToListBestCase-4 100000000 10.4 ns/op

스위치가 끝까지 이기고 최악의 경우가 최상의 경우보다 훨씬 빠릅니다. 지도가 최악이고 목록이 더 가깝습니다.

따라서 도덕은 다음과 같습니다. 정적이고 합리적으로 작은 목록이있는 경우 switch 문을 사용하십시오.


Go가이 경우를 최적화하는지 모르겠지만 목록 / 맵의 초기화를 테스트 함수 밖으로 이동하면 차이가 있습니까?
w00t

나는 비교가 정렬 된 목록으로 어떻게 진행되는지, 그리고 그 정렬이 가치가 있는지를 궁금합니다
Michael Draper

무엇에 대한 :대신 ,스위치 문에서? 더 빨라 집니까?
토마스 Sauvajon

case단일 사례 대신 여러 문을 사용해 보았습니다 . 결과는 두 기능에서 모두 동일합니다.
토마스 Sauvajon

7

다른 옵션은 맵을 세트로 사용하는 것입니다. 키만 사용하고 값이 항상 true 인 부울과 같아야합니다. 그러면지도에 키가 포함되어 있는지 쉽게 확인할 수 있습니다. 이것은 세트의 동작이 필요할 때 유용합니다. 값을 여러 번 추가하면 세트에 한 번만 있습니다.

다음은지도에 임의의 숫자를 키로 추가하는 간단한 예입니다. 같은 숫자가 두 번 이상 생성되면 중요하지 않으며, 최종 맵에만 한 번만 나타납니다. 그런 다음 키가 맵에 있는지 여부를 확인하려면 간단한 경우를 사용하십시오.

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    var MAX int = 10

    m := make(map[int]bool)

    for i := 0; i <= MAX; i++ {
        m[rand.Intn(MAX)] = true
    }

    for i := 0; i <= MAX; i++ {
        if _, ok := m[i]; ok {
            fmt.Printf("%v is in map\n", i)
        } else {
            fmt.Printf("%v is not in map\n", i)
        }
    }
}

여기 운동장에 있어요


0

이것은 파이썬의 "in"연산자의 자연스러운 느낌에 도달 할 수있는 한 가깝습니다. 자신의 유형을 정의해야합니다. 그런 다음 원하는대로 동작하는 "has"와 같은 메소드를 추가하여 해당 유형의 기능을 확장 할 수 있습니다.

package main

import "fmt"

type StrSlice []string

func (list StrSlice) Has(a string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func main() {
    var testList = StrSlice{"The", "big", "dog", "has", "fleas"}

    if testList.Has("dog") {
        fmt.Println("Yay!")
    }
}

정수 또는 내 자신의 다른 구조체를 포함하는 것과 같은 여러 유형의 슬라이스에 대해 이와 같은 몇 가지 공통 사항을 정의하는 유틸리티 라이브러리가 있습니다.

예, 선형 시간으로 실행되지만 요점이 아닙니다. 요점은 Go가 가지고 있고 가지고 있지 않은 공통 언어 구성에 대해 묻고 배우는 것입니다. 좋은 운동입니다. 이 답변이 어리 석거나 유용한 지 여부는 독자에게 달려 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.