Как проверить, содержит ли карта ключ в Go?

Я знаю, что могу перебрать карту m,

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

и искать ключ, но есть ли более эффективный способ проверки существования ключа на карте?

Я не мог найти ответ в спецификации языка.

Ответ 1

Один ответ:

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

Объяснение:

Операторы

if в Go могут включать как условие, так и оператор инициализации. В приведенном выше примере используются оба параметра:

  • инициализирует две переменные - val получит либо значение "foo" из карты, либо "нулевое значение" (в этом случае пустая строка) и ok получит bool, который будет установлен на true, если "foo" действительно присутствовал на карте

  • оценивает ok, который будет true, если "foo" был на карте

Если на карте действительно присутствует "foo", тело оператора if будет выполнено и val будет локальным для этой области.

Ответ 2

В дополнение к спецификации языка программирования Go вы должны прочитать Effective Go. В разделе карт, среди прочего, говорится:

Попытка получить значение карты с ключом, которого нет в Карта вернет нулевое значение для типа записей в карте. Например, если карта содержит целые числа, поиск несуществующего ключ вернет 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")
}

Иногда вам нужно отличить отсутствующую запись от нулевого значения. Есть запись для "UTC" или это 0, потому что это не на карте вообще? Вы можете различать с помощью формы множественного назначения.

var seconds int
var ok bool
seconds, ok = timeZone[tz]

По понятным причинам это называется идиома "запятая нормально". В этом Например, если tz присутствует, секунды будут установлены соответствующим образом и нормально будет правдой; если нет, то секунды будут установлены на ноль, и ОК будет ложный. Здесь функция, которая помещает это вместе с хорошей ошибкой Доклад:

func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Println("unknown time zone:", tz)
    return 0
}

Для проверки наличия на карте, не беспокоясь о фактическом значение, вы можете использовать пустой идентификатор (_) вместо обычного переменная для значения.

_, present := timeZone[tz]

Ответ 3

Искал на список галочек по электронной почте и нашел решение, опубликованное Peter Froehlich 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")
        }
}

Или, более компактно,

if value, ok := dict["baz"]; ok {
    fmt.Println("value: ", value)
} else {
    fmt.Println("key not found")
}

Обратите внимание, что с использованием этой формы оператора if переменные value и ok видны только внутри условий if.

Ответ 4

Короткий ответ

_, exists := timeZone[tz]    // Just checks for key existence
val, exists := timeZone[tz]  // Checks for key existence and retrieves the value

Пример

Вот пример на игровой площадке Go.

Более длинный ответ

В разделе Maps Эффективный переход:

Попытка извлечь значение карты с помощью ключа, отсутствующего на карте, вернет нулевое значение для типа записей на карте. Например, если карта содержит целые числа, поиск несуществующего ключа будет возвращать 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]

Ответ 5

Как отмечалось в других ответах, общее решение заключается в использовании индексного выражения в назначении специальной формы:

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), мы также можем проверить, находится ли ключ на карте сравнивая несвойственную форму (индекс) выражения индекса с нулевым значением:

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.

Использование этой "техники" имеет и другое преимущество: вы можете компактно проверить наличие нескольких ключей (вы не можете сделать это с помощью специальной формы "запятая нормально"). Подробнее об этом: Проверьте, существует ли ключ на нескольких картах в одном условии

Получение нулевого значения типа значения при индексации с несуществующим ключом также позволяет нам удобно использовать карты со значениями 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

См. похожие: Как создать массив, содержащий уникальные строки?

Ответ 6

лучший способ здесь

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

Ответ 7

    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 Есть ли что-нибудь? правда не существует? ложь

Ответ 8

Упоминается в разделе "Индексные выражения".

Индексное выражение на карте a типа map [K] V, используемое в присваивании или инициализации специальной формы

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

дает дополнительное нетипизированное логическое значение. Значение ok равно true, если ключ x присутствует на карте, и false в противном случае.

Ответ 9

Для этой цели можно использовать присвоение двух значений. Пожалуйста, проверьте мой пример программы ниже

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

Ответ 10

Просто используйте

if len(m) == 0 {
    ...
}