Bir haritanın Go'da anahtar içerip içermediğini nasıl kontrol edebilirim?


Yanıtlar:


1473

Bir satır cevap:

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

Açıklama:

ifGo ifadeleri hem bir koşul hem de bir başlatma ifadesi içerebilir. Yukarıdaki örnek her ikisini de kullanır:

  • iki değişkeni ilklendirir - valharitadan "foo" değerini veya "sıfır değeri" (bu durumda boş dize) alır ve haritada "foo" mevcutsa okolarak ayarlanacak bir bool alırtrue

  • değerlendirir ok, olacak true"foo" Harita olsaydı

Haritada gerçekten "foo" varsa, ififadenin gövdesi yürütülür ve valbu kapsamda yerel olur.


2
Bu nasıl çalıştığı daha iyi açıklanabilir (peterSO'nun diğer yorumu gibi)
Chmouel Boudjnah

6
@Kiril var val string = ""aynı kalacaktır, aynı val, ok :=adda yalnızca o blokta görünür olan yeni bir yerel değişken oluşturur.
OneOfOne

1
büyük cevap, bunun karmaşıklığı O (1) diyebilir misiniz?
Mheni

1
@Mheni, burada biraz geç kaldığımı biliyorum, ama bu soru hareket halindeki arama karmaşıklığını tartışıyor. Çoğunlukla itfa edilen karmaşıklık O (1) dir, ancak bu sorunun yanıtlarını okumaya değer.
3ocene

70
Python'lara kıyasla böyle kafa karıştırıcı bir sözdizimi if key in dict.
Pranjal Mittal

130

Go Programlama Dili Spesifikasyonu'na ek olarak , Etkili Go'yu da okumalısınız . Haritalar bölümünde, diğer şeylerin yanı sıra:

Haritada bulunmayan bir anahtarla bir harita değeri getirme girişimi, haritadaki girdilerin türü için sıfır değerini döndürür. Örneğin, harita tamsayılar içeriyorsa, var olmayan bir anahtarın aranması 0 değerini döndürür. Bir küme, değer tipi boole içeren bir harita olarak uygulanabilir. Değeri kümeye koymak için harita girişini true olarak ayarlayın ve ardından basit indeksleme ile test edin.

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

Bazen eksik bir girişi sıfır değerinden ayırmanız gerekir. "UTC" için bir giriş var mı veya haritada olmadığı için bu 0 mı? Birden fazla atama biçimiyle ayrım yapabilirsiniz.

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

Açık nedenlerden dolayı buna “virgül ok” deyimi denir. Bu örnekte, eğer tz mevcutsa, saniyeler uygun şekilde ayarlanacak ve tamam doğru olacaktır; değilse, saniye sıfıra ayarlanır ve tamam yanlış olur. İşte güzel bir hata raporu ile bir araya getiren bir fonksiyon:

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

Gerçek değer hakkında endişelenmeden haritadaki varlığını test etmek için, değer için normal değişken yerine boş tanımlayıcıyı (_) kullanabilirsiniz.

_, present := timeZone[tz]

57

Üzerine arandı go-fındık e-posta listesi ve 11/15/2009 tarihinde Peter Froehlich tarafından yayınlanan bir çözüm buldu.

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

Veya daha kompakt bir şekilde,

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

İfadenin bu biçimini kullanarak if, valueve okdeğişkenlerinin yalnızca ifkoşullar içinde görünür olduğunu unutmayın .


21
Gerçekten sadece anahtarın var olup olmadığıyla ilgileniyorsanız ve değeri umursamıyorsanız, kullanabilirsiniz _, ok := dict["baz"]; ok. _Bölüm geçici bir değişken oluşturmak yerine uzak değerini atar.
Matthew Crumley

26

Kısa cevap

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

Misal

İşte Go Playground'da bir örnek .

Daha Uzun Cevap

Başına Haritalar bölümünde Etkili Go :

Haritada bulunmayan bir anahtarla bir harita değeri getirme girişimi, haritadaki girdilerin türü için sıfır değerini döndürür. Örneğin, harita tamsayılar içeriyorsa, var olmayan bir anahtarı aramak 0 değerini döndürür.

Bazen eksik bir girişi sıfır değerinden ayırmanız gerekir. "UTC" için bir giriş var mı veya boş bir dize var mı, çünkü haritada hiç yok mu? Birden fazla atama biçimiyle ayrım yapabilirsiniz.

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

Açık nedenlerden dolayı buna “virgül ok” deyimi denir. Bu örnekte, eğer tz mevcutsa, saniyeler uygun şekilde ayarlanacak ve tamam doğru olacaktır; değilse, saniye sıfıra ayarlanır ve tamam yanlış olur. İşte güzel bir hata raporu ile bir araya getiren bir fonksiyon:

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

Gerçek değer hakkında endişelenmeden haritadaki varlığını test etmek için, değer için normal değişken yerine boş tanımlayıcıyı (_) kullanabilirsiniz.

_, present := timeZone[tz]

13

Diğer cevaplarda belirtildiği gibi, genel çözüm, özel formun bir atamasında bir dizin ifadesi kullanmaktır :

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

Bu güzel ve temiz. Bununla birlikte bazı kısıtlamaları vardır: özel bir form ataması olmalıdır. Sağ taraftaki ifade yalnızca harita dizini ifadesi olmalı ve sol taraftaki ifade listesi, önce değer türünün atanabildiği tam olarak 2 işlenen ve değerin atanabileceği ikinci bir işlenen içermelidir bool. Bu özel formun sonucunun ilk değeri, anahtarla ilişkili değer olacaktır ve ikinci değer, haritada verilen anahtarla gerçekten bir giriş olup olmadığını (anahtar haritada varsa) söyleyecektir. Sol taraftaki ifade listesi , sonuçlardan birine ihtiyaç duyulmadığında da boş tanımlayıcı içerebilir .

Dizinlenmiş harita değeri nilanahtar içeriyorsa veya anahtar içermiyorsa, dizin ifadesinin haritanın değer türünün sıfır değerini değerlendirdiğini bilmek önemlidir . Yani mesela:

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 Playground'da deneyin .

Dolayısıyla, haritamızda sıfır değerini kullanmadığımızı bilirsek, bundan yararlanabiliriz.

Örneğin, değer türü ise stringve girişleri haritada değerin boş dize ( stringtür için sıfır değeri ) olduğu yerde saklamamış olduğumuzu biliyoruz , özel olmayanları karşılaştırarak anahtarın haritada olup olmadığını da test edebiliriz dizin ifadesinin (sonucunun) sıfır değerine biçimi:

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

Çıktı ( Go Playground'da deneyin ):

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

Uygulamada, sıfır değer değerini haritada saklamadığımız birçok durum vardır, bu nedenle bu oldukça sık kullanılabilir. Örneğin, arayüzler ve işlev türlerinin sıfır değeri vardır nilve bunlar genellikle haritalarda saklamayız. Böylece bir anahtarın haritada olup olmadığını test etmek, karşılaştırmak suretiyle elde edilebilir nil.

Bu "tekniği" kullanmanın başka bir avantajı daha vardır: birden çok anahtarın varlığını kompakt bir şekilde kontrol edebilirsiniz (bunu özel "virgül ok" formuyla yapamazsınız). Bununla ilgili daha fazla bilgi: Bir koşulda birden çok haritada anahtar olup olmadığını kontrol edin

Mevcut olmayan bir anahtarla dizin oluştururken değer türünün sıfır değerini elde etmek, booldeğerleri olan haritaları set olarak kullanmamızı da sağlar . Örneğin:

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

Çıktı verir ( Go Playground'da deneyin ):

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

İlgili bilgilere bakın: Benzersiz dizeler içeren bir diziyi nasıl oluşturabilirim?


1
ne Tde var v, ok T = a[x]? değil okbool olmalı?
Kokizzu

2
@Kokizzu Bu değişken bildirimin genel biçimidir. İlk başta haritası tipte olsaydı sadece (derleme) çalışacak düşünebilir map[bool]boolve Tbir bool, ancak harita türü ise o da çalışır map[interface{}]boolve Tolduğu interface{}; ayrıca booltemel türü olan özel türlerle de çalışır , Go Playground'daki hepsini görün . Yani bu form ikame edilmiş birden çok tip için geçerli olduğundan T, bu yüzden genel Tkullanılır. Türü, türlenmemiş olarak atanabilecek okherhangi bir şey olabilir. bool
icza


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

3
    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)

Sonra go run maps.go bir şey var mı? doğru yok mu? yanlış


Int için ihtiyaçtan kurtulur
Lady_Exotel

Katkınız için teşekkürler, ancak mevcut cevapların soruyu iyi kapsadığını düşünüyorum. Burada söylediklerinizden cevabınız Go tür soru setinde en iyi uygulama yöntemine daha uygun olacaktır .
tomasz

_, ok = m["somestring"]olmalı=_, ok := m["somestring"]
Elroy Jetson

3

"Dizin ifadeleri" altında belirtilmiştir .

Özel formun atanmasında veya başlatılmasında kullanılan harita [A] tipi haritadaki bir dizin ifadesi

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

ek bir tiplenmemiş boole değeri verir. Haritada x tuşu varsa ok değeri true, aksi takdirde false olur.


1

Bu amaçla iki değer ataması kullanılabilir. Lütfen aşağıdaki örnek programımı kontrol edin

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")
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.