如何在Go中检查地图是否包含某个键?

huangapple go评论76阅读模式
英文:

How to check if a map contains a key in Go?

问题

我知道我可以使用以下方式遍历map m

for k, v := range m { ... }

并查找一个键,但是有没有更高效的方法来测试一个键是否存在于map中?

英文:

I know I can iterate over a map m with

for k, v := range m { ... }

and look for a key, but is there a more efficient way of testing for a key's existence in a map?

答案1

得分: 2522

这是如何检查一个map是否包含一个键的方法。

val, ok := myMap["foo"]
// 如果键存在
if ok {
    // 做一些操作
}

这里初始化了两个变量。val是map中键"foo"的值,如果存在的话,否则是一个"零值"(在这种情况下是空字符串)。ok是一个bool类型的变量,如果键存在,则设置为true

如果你愿意,你可以将其简化为一行代码。

if val, ok := myMap["foo"]; ok {
    // 在这里做一些操作
}

Go语言允许在if语句中的条件之前放置一个初始化语句(注意分号)。这样做的结果是,valok的作用域将被限制在if语句的主体中,这对于只需要在那里访问它们非常有帮助。

英文:

Here's how you check if a map contains a key.

val, ok := myMap["foo"]
// If the key exists
if ok {
    // Do something
}

This initializes two variables. val is the value of "foo" from the map if it exists, or a "zero value" if it doesn't (in this case the empty string). ok is a bool that will be set to true if the key existed.

If you want, you can shorten this to a one-liner.

if val, ok := myMap["foo"]; ok {
    //do something here
}

Go allows you to put an initializing statement before the condition (notice the semicolon) in the if statement. The consequence of this is that the scope ofval and ok will be limited to the body of the if statement, which is helpful if you only need to access them there.

答案2

得分: 198

除了Go编程语言规范之外,你还应该阅读Effective Go。在关于maps的部分,他们说,除其他事项外:

> 尝试使用不存在于map中的键来获取map值将返回map中条目类型的零值。
> 例如,如果map包含整数,查找一个不存在的键将返回0。可以将集合实现为值类型为bool的map。将map条目设置为true以将值放入集合中,然后通过简单的索引进行测试。
>
> attended := map[string]bool{
> "Ann": true,
> "Joe": true,
> ...
> }
>
> if attended[person] { // 如果person不在map中,则为false
> fmt.Println(person, "参加了会议")
> }
>
> 有时你需要区分缺失的条目和零值。是否有"UTC"的条目,还是因为根本不在map中而为0?你可以使用多重赋值的形式进行区分。
>
> var seconds int
> var ok bool
> seconds, ok = timeZone[tz]
>
> 由于明显的原因,这被称为“逗号ok”习语。在这个例子中,如果tz存在,seconds将被适当设置,ok将为true;如果不存在,seconds将被设置为零,ok将为false。下面是一个将其与一个漂亮的错误报告结合起来的函数:
>
> func offset(tz string) int {
> if seconds, ok := timeZone[tz]; ok {
> return seconds
> }
> log.Println("未知的时区:", tz)
> return 0
> }
>
> 如果只关心map中是否存在而不关心实际值,可以使用空白标识符(_)代替通常用于值的变量。
>
> _, present := timeZone[tz]

英文:

In addition to The Go Programming Language Specification, you should read Effective Go. In the section on maps, they say, amongst other things:

> 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. A set can be implemented as a map with value type
> bool. Set the map entry to true to put the value in the set, and then
> test it by simple indexing.
>
> 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")
> }
>
> Sometimes you need to distinguish a missing entry from a zero value.
> Is there an entry for "UTC" or is that 0 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]

答案3

得分: 112

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

注意,使用这种形式的if语句,valueok变量只在if条件内可见。

英文:

Searched on the go-nuts email list and found a solution posted by Peter Froehlich on 11/15/2009.

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

Or, more compactly,

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.

答案4

得分: 54

简短回答

_, exists := timeZone[tz]    // 只检查键是否存在
val, exists := timeZone[tz]  // 检查键是否存在并获取值

示例

这是一个在Go Playground上的示例

较长回答

根据Effective Go中的Maps部分:

> 尝试使用在映射中不存在的键获取映射值将返回映射条目类型的零值。例如,如果映射包含整数,查找一个不存在的键将返回0。
>
> 有时,您需要区分缺失的条目和零值。是否存在“UTC”条目,还是因为根本不在映射中而是空字符串?您可以使用一种多重赋值的形式进行区分。
>
> var seconds int
> var ok bool
> seconds, ok = timeZone[tz]
>
> 基于明显的原因,这被称为“逗号ok”习语。在这个示例中,如果tz存在,seconds将被适当设置,并且ok将为true;如果不存在,seconds将被设置为零,ok将为false。下面是一个将其与一个漂亮的错误报告结合在一起的函数:
>
> func offset(tz string) int {
> if seconds, ok := timeZone[tz]; ok {
> return seconds
> }
> log.Println("unknown time zone:", tz)
> return 0
> }
>
> 如果只关心映射中是否存在而不关心实际值,可以使用空白标识符(_)代替通常用于值的变量。
>
> _, present := timeZone[tz]

英文:

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]

答案5

得分: 40

看一下这段代码

nameMap := make(map[string]int)
nameMap["river"] = 33
v ,exist := nameMap["river"]
if exist {
	fmt.Println("存在 ",v)
}
英文:

Have a look at this snippet of code

nameMap := make(map[string]int)
nameMap["river"] = 33
v ,exist := nameMap["river"]
if exist {
	fmt.Println("exist ",v)
}

答案6

得分: 27

正如其他答案所指出的,一般解决方案是在特殊形式的赋值语句中使用索引表达式:

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]

这样做很简洁明了。但是它也有一些限制:它必须是特殊形式的赋值语句。右侧表达式必须是映射索引表达式,并且左侧表达式列表必须恰好包含2个操作数,第一个操作数的值类型可赋值,第二个操作数可赋值为bool值。这个特殊形式的结果的第一个值将是与键关联的值,第二个值将告诉我们是否实际上在映射中存在具有给定键的条目(如果键存在于映射中)。左侧表达式列表还可以包含空白标识符,如果其中一个结果不需要的话。

重要的是要知道,如果索引映射值为nil或不包含键,则索引表达式将求值为映射值类型的零值。例如:

m := map[int]string{}
s := m[1] // s将是空字符串""
var m2 map[int]float64 // m2是nil!
f := m2[2] // f将是0.0

fmt.Printf("%q %f", s, f) // 输出:"\"\" 0.000000"

Go Playground上尝试一下。

因此,如果我们知道在映射中不使用零值,我们可以利用这一点。

例如,如果值类型是string,并且我们知道我们从不在映射中存储值为空字符串的条目(string类型的零值),我们还可以通过将(索引表达式的结果)的非特殊形式与零值进行比较来测试键是否在映射中:

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] != "")

输出结果(在Go Playground上尝试):

Key 0 exists: true
Key 1 exists: true
Key 2 exists: false

实际上有很多情况下我们不会在映射中存储零值,所以这种方法可以经常使用。例如,接口和函数类型的零值是nil,我们通常不会将其存储在映射中。因此,通过将其与nil进行比较,可以检查键是否在映射中。

使用这种“技巧”还有另一个好处:可以以紧凑的方式检查多个键的存在性(使用特殊的“逗号-OK”形式无法做到这一点)。更多相关信息请参阅:https://stackoverflow.com/questions/41978101/check-if-key-exists-in-multiple-maps-in-one-condition/41978277#41978277

当使用不存在的键进行索引时,获取值类型的零值还允许我们方便地使用bool值的映射作为“集合”。例如:

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

输出结果(在Go Playground上尝试):

Contains 'one': true
'two' is in the set
'three' is not in the set

参考链接:https://stackoverflow.com/questions/33207197/how-can-i-create-an-array-that-contains-unique-strings/33207265#33207265

英文:

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: https://stackoverflow.com/questions/41978101/check-if-key-exists-in-multiple-maps-in-one-condition/41978277#41978277

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: https://stackoverflow.com/questions/33207197/how-can-i-create-an-array-that-contains-unique-strings/33207265#33207265

答案7

得分: 26

var d map[string]string
value, ok := d["key"]
if ok {
	fmt.Println("Key Present ", value)
} else {
	fmt.Println(" Key Not Present ")
}
英文:
var d map[string]string
value, ok := d["key"]
if ok {
	fmt.Println("Key Present ", value)
} else {
	fmt.Println(" Key Not Present ")
}

答案8

得分: 6

var empty struct{}
var ok bool
var m map[string]struct{}
m = make(map[string]struct{})
m["somestring"] = empty

_, ok = m["somestring"]
fmt.Println("字符串存在?", ok)
_, ok = m["not"]
fmt.Println("不存在?", ok)

然后,运行 maps.go
字符串存在? true
不存在? false

英文:
    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

答案9

得分: 5

它在“索引表达式”下提到。

> 在赋值或初始化的特殊形式中,对于类型为map[K]V的映射a上的索引表达式

>

> v, ok = a[x]
> v, ok := a[x]
> var v, ok = a[x]

>

> 会产生一个额外的无类型布尔值。如果键x在映射中存在,则ok的值为true,否则为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.

答案10

得分: 4

一个两个值的赋值可以用于这个目的。请查看下面的示例程序

package main

import (
    "fmt"
)

func main() {
    //创建一个包含3个键值对的映射
    sampleMap := map[string]int{"key1": 100, "key2": 500, "key3": 999}
    //可以使用两个值的赋值来检查键是否存在。
    value, isKeyPresent := sampleMap["key2"]
    //如果键存在于sampleMap中,isKeyPresent将为true
    if isKeyPresent {
        //键存在
        fmt.Println("键存在,值为", value)
    } else {
        //键不存在
        fmt.Println("键不存在")
    }
}
英文:

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

答案11

得分: -4

示例用法:循环遍历切片,对于pairMap检查键是否存在。
这是一个找到所有相加等于特定和的配对的算法。

func findPairs(slice1 []int, sum int) {
	pairMap := make(map[int]int)
	for i, v := range slice1 {
		if valuei, ok := pairMap[v]; ok {
			fmt.Println("找到配对", i, valuei)
		} else {
			pairMap[sum-v] = i
		}
	}
}
英文:

Example usage: Looping through a slice, for pairMap checking if key exists.
It an algorithm to find all pairs that adds to a specific sum.

func findPairs(slice1 []int, sum int) {
	pairMap := make(map[int]int)
	for i, v := range slice1 {
		if valuei, ok := pairMap[v]; ok {
			fmt.Println("Pair Found", i, valuei)
		} else {
			pairMap[sum-v] = i
		}
	}
}

huangapple
  • 本文由 发表于 2010年1月13日 00:18:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/2050391.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定