지도에 Go의 키가 포함되어 있는지 확인하는 방법은 무엇입니까?
나는 내가지도 m
를 반복 할 수 있다는 것을 안다 .
for k, v := range m { ... }
키를 찾지 만 맵에서 키의 존재를 테스트하는 더 효율적인 방법이 있습니까?
언어 사양 에서 답을 찾을 수 없습니다 .
한 줄 대답 :
if val, ok := dict["foo"]; ok {
//do something here
}
설명:
if
Go의 문은 조건문과 초기화 문을 모두 포함 할 수 있습니다. 위의 예는 다음을 모두 사용합니다.
두 개의 변수를 초기화합니다.-
val
맵에서 "foo"값 또는 "0 값"(이 경우 빈 문자열)ok
을 수신하고true
"foo"가 실제로 맵에 존재 하는 경우 로 설정되는 bool을 수신합니다.평가하여이
ok
될 것이다true
"foo는"이지도에 있었다면
"foo"가 실제로 맵에 있으면 if
명령문 의 본문 이 실행되고 val
해당 범위에 국한됩니다.
Go 프로그래밍 언어 사양 외에도 Effective Go를 읽어야 합니다 . 지도 섹션에서 그들은 무엇보다도 다음과 같이 말합니다.
맵에없는 키로 맵 값을 가져 오려고하면 맵의 항목 유형에 대해 0 값이 반환됩니다. 예를 들어 맵에 정수가 포함 된 경우 존재하지 않는 키를 검색하면 0이 반환됩니다. 집합은 bool 값 유형의 맵으로 구현 될 수 있습니다. 맵 항목을 true로 설정하여 값을 세트에 넣은 다음 간단한 인덱싱으로 테스트합니다.
attended := map[string]bool{ "Ann": true, "Joe": true, ... } if attended[person] { // will be false if person is not in the map fmt.Println(person, "was at the meeting") }
누락 된 항목을 0 값과 구별해야하는 경우가 있습니다. "UTC"에 대한 항목이 있습니까? 아니면 맵에 전혀 없기 때문에 0입니까? 다중 할당의 형태로 구별 할 수 있습니다.
var seconds int var ok bool seconds, ok = timeZone[tz]
명백한 이유로 이것을 "comma ok"관용구라고합니다. 이 예에서 tz가 있으면 초가 적절하게 설정되고 ok는 참이됩니다. 그렇지 않은 경우 초는 0으로 설정되고 ok는 거짓입니다. 다음은 멋진 오류 보고서와 함께 제공하는 함수입니다.
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
실제 값에 대해 걱정하지 않고지도에서 존재 여부를 테스트하려면 값에 대한 일반적인 변수 대신 빈 식별자 (_)를 사용할 수 있습니다.
_, present := timeZone[tz]
go-nuts 이메일 목록 에서 검색 한 결과 Peter Froehlich가 2009 년 11 월 15 일에 게시 한 솔루션을 찾았습니다.
package main
import "fmt"
func main() {
dict := map[string]int {"foo" : 1, "bar" : 2}
value, ok := dict["baz"]
if ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
}
또는 더 간결하게
if value, ok := dict["baz"]; ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
Note, using this form of the if
statement, the value
and ok
variables are only visible inside the if
conditions.
Short Answer
_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
Example
Here's an example at the Go Playground.
Longer Answer
Per the Maps section of Effective Go:
An attempt to fetch a map value with a key that is not present in the map will return the zero value for the type of the entries in the map. For instance, if the map contains integers, looking up a non-existent key will return 0.
Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that the empty string because it's not in the map at all? You can discriminate with a form of multiple assignment.
var seconds int var ok bool seconds, ok = timeZone[tz]
For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false. Here's a function that puts it together with a nice error report:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
To test for presence in the map without worrying about the actual value, you can use the blank identifier (_) in place of the usual variable for the value.
_, present := timeZone[tz]
As noted by other answers, the general solution is to use an index expression in an assignment of the special form:
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
This is nice and clean. It has some restrictions though: it must be an assignment of special form. Right-hand side expression must be the map index expression only, and the left-hand expression list must contain exactly 2 operands, first to which the value type is assignable, and a second to which a bool
value is assignable. The first value of the result of this special form will be the value associated with the key, and the second value will tell if there is actually an entry in the map with the given key (if the key exists in the map). The left-hand side expression list may also contain the blank identifier if one of the results is not needed.
It's important to know that if the indexed map value is nil
or does not contain the key, the index expression evaluates to the zero value of the value type of the map. So for example:
m := map[int]string{}
s := m[1] // s will be the empty string ""
var m2 map[int]float64 // m2 is nil!
f := m2[2] // f will be 0.0
fmt.Printf("%q %f", s, f) // Prints: "" 0.000000
Try it on the Go Playground.
So if we know that we don't use the zero value in our map, we can take advantage of this.
For example if the value type is string
, and we know we never store entries in the map where the value is the empty string (zero value for the string
type), we can also test if the key is in the map by comparing the non-special form of the (result of the) index expression to the zero value:
m := map[int]string{
0: "zero",
1: "one",
}
fmt.Printf("Key 0 exists: %t\nKey 1 exists: %t\nKey 2 exists: %t",
m[0] != "", m[1] != "", m[2] != "")
Output (try it on the Go Playground):
Key 0 exists: true
Key 1 exists: true
Key 2 exists: false
In practice there are many cases where we don't store the zero-value value in the map, so this can be used quite often. For example interfaces and function types have a zero value nil
, which we often don't store in maps. So testing if a key is in the map can be achieved by comparing it to nil
.
Using this "technique" has another advantage too: you can check existence of multiple keys in a compact way (you can't do that with the special "comma ok" form). More about this: Check if key exists in multiple maps in one condition
Getting the zero value of the value type when indexing with a non-existing key also allows us to use maps with bool
values conveniently as sets. For example:
set := map[string]bool{
"one": true,
"two": true,
}
fmt.Println("Contains 'one':", set["one"])
if set["two"] {
fmt.Println("'two' is in the set")
}
if !set["three"] {
fmt.Println("'three' is not in the set")
}
It outputs (try it on the Go Playground):
Contains 'one': true
'two' is in the set
'three' is not in the set
See related: How can I create an array that contains unique strings?
better way here
if _, ok := dict["foo"]; ok {
//do something here
}
var empty struct{}
var ok bool
var m map[string]struct{}
m = make(map[string]struct{})
m["somestring"] = empty
_, ok = m["somestring"]
fmt.Println("somestring exists?", ok)
_, ok = m["not"]
fmt.Println("not exists?", ok)
Then, go run maps.go somestring exists? true not exists? false
It is mentioned under "Index expressions".
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
A two value assignment can be used for this purpose. Please check my sample program below
package main
import (
"fmt"
)
func main() {
//creating a map with 3 key-value pairs
sampleMap := map[string]int{"key1": 100, "key2": 500, "key3": 999}
//A two value assignment can be used to check existence of a key.
value, isKeyPresent := sampleMap["key2"]
//isKeyPresent will be true if key present in sampleMap
if isKeyPresent {
//key exist
fmt.Println("key present, value = ", value)
} else {
//key does not exist
fmt.Println("key does not exist")
}
}
참고URL : https://stackoverflow.com/questions/2050391/how-to-check-if-a-map-contains-a-key-in-go
'developer tip' 카테고리의 다른 글
휘발성 vs. 연동 vs. 잠금 (0) | 2020.10.02 |
---|---|
프로젝트 오일러와 속도 비교 : C vs Python vs Erlang vs Haskell (0) | 2020.10.02 |
1MB RAM에서 1 백만 개의 8 자리 숫자 정렬 (0) | 2020.10.02 |
Interop 유형은 삽입 할 수 없습니다. (0) | 2020.10.02 |
Swift에서 문자열을 배열로 분할 하시겠습니까? (0) | 2020.10.02 |