Как проверить, есть ли на карте ключ?
Я знаю, что могу перебрать карту m
от,
for k, v := range m { ... }
и искать ключ, но есть ли более эффективный способ проверки существования ключа на карте?
Я не мог найти ответ в спецификации языка.
13 ответов
Ответ в одну строку:
if val, ok := dict["foo"]; ok {
//do something here
}
Объяснение:
if
Операторы в Go могут включать как условие, так и оператор инициализации. В приведенном выше примере используются оба:
инициализирует две переменные -
val
получит либо значение "foo" с карты, либо "нулевое значение" (в данном случае пустую строку) иok
получит bool, который будет установлен вtrue
если "foo" действительно присутствовал на картеоценивает
ok
, которые будутtrue
если "Foo" был на карте
Если "foo" действительно присутствует на карте, тело if
заявление будет выполнено и val
будет локальным для этой области.
Редактировать: следующий ответ до перехода к Go 1. Начиная с Go 1, он больше не является точным / действительным.
В дополнение к спецификации языка программирования Go вы должны прочитать Effective Go. В разделе о картах, среди прочего, говорится:
"Попытка получить значение карты с ключом, которого нет на карте, приведет к сбою программы, но есть способ сделать это безопасно, используя множественное назначение".
var seconds int
var ok bool
seconds, ok = timeZone[tz]
"Чтобы проверить наличие на карте, не беспокоясь о фактическом значении, вы можете использовать пустой идентификатор, простое подчеркивание (_). Пустой идентификатор может быть назначен или объявлен с любым значением любого типа, причем значение отбрасывается безвредно. Для проверки присутствия на карте используйте пустой идентификатор вместо обычной переменной для значения."
_, present := timeZone[tz]
Поиск по списку рассылок и поиск решения, размещенного Питером Фрёлихом 15/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")
}
}
Или, более компактно,
if value, ok := dict["baz"]; ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
Обратите внимание, используя эту форму if
заявление, value
а также ok
переменные видны только внутри if
условия.
Короткий ответ
_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
пример
Вот пример на игровой площадке Go.
Более длинный ответ
В разделе " Карты " Effective Go:
Попытка получить значение карты с ключом, которого нет на карте, вернет нулевое значение для типа записей в карте. Например, если карта содержит целые числа, поиск несуществующего ключа вернет 0.
Иногда вам нужно отличить отсутствующую запись от нулевого значения. Есть ли запись для "UTC" или это пустая строка, потому что ее нет на карте вообще? Вы можете различать с помощью формы множественного назначения.
var seconds int var ok bool seconds, ok = timeZone[tz]
По понятным причинам это называется "запятая нормально". В этом примере, если tz присутствует, секунды будут установлены соответствующим образом, и ok будет истинным; если нет, то секунды будут установлены на ноль, и 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]
Взгляните на этот фрагмент кода
nameMap := make(map[string]int)
nameMap["river"] = 33
v ,exist := nameMap["river"]
if exist {
fmt.Println("exist ",v)
}
var d map[string]string
value, ok := d["key"]
if ok {
fmt.Println("Key Present ", value)
} else {
fmt.Println(" Key Not Present ")
}
Как отмечено другими ответами, общее решение состоит в том, чтобы использовать индексное выражение в присваивании специальной формы:
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 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
Попробуйте это на игровой площадке Go.
Поэтому, если мы знаем, что не используем нулевое значение на нашей карте, мы можем воспользоваться этим.
Например, если тип значения string
и мы знаем, что никогда не сохраняем записи на карте, где значение является пустой строкой (нулевое значение для string
type), мы также можем проверить, находится ли ключ на карте, сравнив несвойственную форму (результат) выражения index с нулевым значением:
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
,
Использование этой "техники" имеет и другое преимущество: вы можете компактно проверить наличие нескольких ключей (вы не можете сделать это с помощью специальной формы "запятая нормально"). Подробнее об этом: Проверьте, существует ли ключ на нескольких картах в одном условии
Лучший способ здесь
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)
Тогда иди запусти maps.go что-нибудь существует? правда не существует? ложный
Упоминается в разделе "Индексные выражения".
Индексное выражение на карте a типа map[K]V, используемое в присваивании или инициализации специальной формы
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
дает дополнительное нетипизированное логическое значение. Значение ok равно true, если ключ x присутствует на карте, и false в противном случае.
Для этой цели можно использовать присвоение двух значений. Пожалуйста, проверьте мой пример программы ниже
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")
}
}
Пример использования: Цикл по срезу, для проверки 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("Pair Found", i, valuei)
} else {
pairMap[sum-v] = i
}
}
}