Kotlin’in varsayılan bir haritası var mı?

Diğer defaultdicttiplerle de kullanılabilir ve KeyErrorkodunuzu çalıştırırken bir alamadığınızdan emin olun . Bunun yerine, bilinmeyen anahtarlar için varsayılan bir değer sağlar; bu, aşağıdakiler gibi algoritmaları gruplamak ve saymak için gerçekten yararlı olabilir:

Daha önce hiç varsayılan harita veya varsayılan dict kullandınız mı? Python’u biraz tanıyorsanız, muhtemelen bir defaultdictnoktada eylemde olduğunu gördünüz . Kotlin de bu küçük makalede göstermek istediğim benzer bir araçla geliyor.
Python defaultdictbelgelerini ve bazı örnekleri burada bulabilirsiniz, ancak temel kullanım durumu aşağıdaki kod parçasında gösterilmektedir:

from collections import defaultdict 

d = defaultdict(int)
print(d["someKey"]) //0

Diğer defaultdicttiplerle de kullanılabilir ve KeyErrorkodunuzu çalıştırırken bir alamadığınızdan emin olun . Bunun yerine, bilinmeyen anahtarlar için varsayılan bir değer sağlar; bu, aşağıdakiler gibi algoritmaları gruplamak ve saymak için gerçekten yararlı olabilir:

from collections import defaultdict 

data = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = defaultdict(set)
for k, v in data:
    d[k].add(v)

print(d.items()) # dict_items([('red', {1, 3}), ('blue', {2, 4})])

Bu yazıda size Kotlin’in varsayılan harita değerlerini nasıl kullandığını ve diğer alternatiflerin neler olduğunu göstermek istiyorum.

Basit bir problem

Bir koleksiyon alan ve orijinal koleksiyondaki öğeleri içeren bir harita döndüren ve bunların sayısıyla ilişkili genel bir işlev yazmak istediğimizi varsayalım:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int>

Elbette, Kotlin’de bunu yapmanın doğal ve kolay bir işlevsel stil yolu olmasına rağmen, önce bazı yinelemeli yaklaşımları düşünmek istiyoruz. Aşağıdaki ile başlayalım.

Varsayılansız yinelemeli çözüm

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> {
    val countMap = mutableMapOf<T, Int>()
    for (e in values) {
        val current = countMap[e]
        if (current == null) countMap[e] = 1 
        else countMap[e] = current + 1
    }
    return countMap
}

MutableMapBu algoritma için bir kullanabiliriz . Tüm değerleri tekrarlarken, daha önce görülüp görülmediğini görmek için haritanın içine bakarız. Öyleyse, sayacı artırırız; aksi takdirde, 1haritanın ilk sayısını koyarız . Benzer, ancak geliştirilmiş bir çözüm bir sonraki bölümde gösterilmektedir.

Açık varsayılanlarla yinelemeli çözüm

//sampleStart
countMap.putIfAbsent(e, 0)
// getValue, as an alternative to index operator, assures that a non-nullable type is returned
countMap[e] = countMap.getValue(e) + 1 

Önceki çözümün bir alternatifi olarak, putIfAbsentelemanın 0 ile başlatıldığından emin olmak için faydalanabiliriz, böylece sayacı aşağıdaki satırda güvenle artırabiliriz. Bu durumda yaptığımız şey açık bir varsayılan değer sağlamaktır. Başka bir benzer araç getOrDefault:

countMap[e] = countMap.getOrDefault(e, 0) + 1

Açık varsayılanları sağlayarak putIfAbsentveya getOrDefaultkolay ve anlaşılır çözümlerle yönlendirir, ancak daha iyisini yapabiliriz.

Kapalı varsayılanlarla yinelemeli çözüm

Python’a benzer şekilde defaultdict, Kotlin denilen temiz bir uzantıyla gelir MutableMap::withDefaultve şöyle görünür:

fun <K, V> MutableMap<K, V>.withDefault(defaultValue: (key: K) -> V): MutableMap<K, V>

Bu uzantı, haritada ilişkilendirilmiş bir değeri olmayan anahtarlar için bir başlatıcı sunalım. Bizim çözümümüzde kullanalım:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> {
    val countMap = mutableMapOf<T, Int>().withDefault { 0 }
    for (e in values) {
        countMap[e] = countMap.getValue(e) + 1
    }
    return countMap
}

Artık, yinelemede bilinmeyen değerlerle uğraşmamız gerekmediği için kodu daha da kolaylaştırır. Varsayılan bir harita kullandığımızdan, ondan güvenle değer alabilir ve kullandığımız sayacı artırabiliriz.

Önemli Not

Eklentiyi kullanırken, withDefaultdokümantasyonunun bir parçası olarak bilmeniz gereken önemli bir şey var :

[…] Bu örtük varsayılan değer, orijinal harita belirtilen anahtar için bir değer içermediğinde ve [Map.getValue] işlevi […] ile bir değer elde edildiğinde kullanılır

Varsayılan değer yalnızca kullanırsanız Map::getValue, haritaya burada gözlemleyebileceğiniz gibi indeks operatörleri ile erişilirken geçerli değildir (çalıştır düğmesine basın):

fun main(){
    val map = mutableMapOf<String, Int>().withDefault { 0 }
    println(map["hello"])
    println(map.getValue("hello")) 
}

Bunun nedeni, Maparayüzün sözleşmesidir :

Verilen [tuşa] karşılık gelen değeri ya nullda böyle bir tuş haritada yoksa değeri döndürür .

Varsayılan haritalar bu sözleşmeyi yerine getirmek istediğinden null, daha önce Kotlin forumunda tartışılan mevcut olmayan anahtarlar durumunda hiçbir şey iade edemezler .

Deyimsel gidelim

Pekâlâ, Kotlin’in gerçekten haritalardaki varsayılan değerlerle birlikte geldiğini gördüm, bu harika. Ancak yine de yukarıdaki örneklerde yaptığımız gibi kod yazmak aptalca mı? Bence buna bağlı. Kotlin’in yerleşik gruplama ve sayma işlevselliklerine sahip üstün fonksiyonel API’leri kullanarak çoğu durumda daha kolay çözülebilir. Bununla birlikte, alternatifleri bilmek iyidir, çünkü bazı durumlarda yinelemeli bir yaklaşımla gitmeyi tercih edebilirsiniz. Size kodumuzun basitleştirilmiş bir versiyonunu vereyim:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> =
    mutableMapOf<T, Int>().withDefault { 0 }.apply {
        for (e in values) {
            put(e, getValue(e) + 1)
        }
    }

Hala açık bir fordöngü kullanıyor ancak kullanımı applytek bir ifadeyle haritayı başlatmamıza olanak veren kullanımıyla sadeleşti .

Orada KOTLIN verilen sorunu çözmek için onlarca yol vardır, ama muhtemelen en basit bir olan fonksiyonel bir yaklaşım:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> =
    values.groupingBy { it }.eachCount()

Sonuç

Bu küçük makalede gösterildiği gibi, basit algoritmaları Kotlin’i kullanarak birçok farklı şekilde çözebilirsiniz. Python’a benzer şekilde, varsayılan bir değer sağlayıcılı bir haritayı başlatabilirsiniz, ancak düzenli dizin işlem erişiminin beklediğiniz gibi çalışmadığını bilmeniz gerekir. Belgelendiği gibi, getValuefonksiyon kullanılmalıdır. Kotlin çok kullanışlı bir standart kütüphane ile birlikte geldiğinden, mümkün olduğunca kullanmayı düşünmek istersiniz. Bu, gruplama veya sayma gibi yaygın şeylerin uygulanmasının, çoğu durumda sıfırdan uygulanmaması, aksine standart kütüphanedeki mevcut işlevlerle yapılması gerektiği anlamına gelir.

Comments

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

GIPHY App Key not set. Please check settings

Yükleniyor…

0

Ne düşünüyorsun?

Son yıllarda yeniden tasarlanan ve Mercedes-Benz serisindeki en eski hafif kamyonlardan biri olan saygıdeğer G sınıfının pille çalışan bir çeşidi, çevrecilerin yüksek emisyonlara sahip ağır, daha az verimli SUV'leri hedef aldığı bir zamanda modelin geleceğini güvence altına almaya yardımcı olabilir .

Mercedes, G sınıfını elektirikli yapmayı planlıyor.

BMW, 12 milyar avroluk (14 milyar dolarlık) maliyet düşürücü tahribatın ortasında, otomobillerin vardiyasıyla ilgili artan maliyetlerle mücadele ederken, endüstrinin nesillerindeki dönüşümünü gerçekleştirmenin zorluklarına ek olarak talep sıkıntıları da beraberinde getiriyor.

BMW, elektrifikasyona geçiş