Standart Kotlin kütüphanesinde hangi Java 8 Stream.collect eşdeğerleri bulunmaktadır?


181

Java 8'de, Stream.collectkoleksiyonlarda toplamalara izin veren var . Kotlin'de bu, stdlib'deki uzatma işlevlerinin bir koleksiyonu olarak değil, aynı şekilde mevcut değildir. Ancak farklı kullanım durumları için denkliklerin ne olduğu açık değildir.

Örneğin , JavaDoc'un üst kısmındaCollectors Java 8 için yazılmış örnekler vardır ve bunları Kolin'e taşırken, farklı bir JDK sürümündeyken Java 8 sınıflarını kullanamazsınız, bu nedenle muhtemelen farklı yazılmalıdır.

Kotlin koleksiyonlarının örneklerini gösteren çevrimiçi kaynaklar açısından, bunlar genellikle önemsizdir ve aynı kullanım durumlarıyla gerçekten karşılaştırılmazlar. Java 8 için belgelenmiş gibi durumlarla gerçekten eşleşen iyi örnekler nelerdir Stream.collect? Buradaki liste:

  • Listede isimleri biriktirme
  • TreeSet içinde isimleri biriktirme
  • Öğeleri dizelere dönüştürün ve virgülle ayırarak birleştirin
  • Çalışan maaşlarının toplamını hesapla
  • Bölümlere göre grup çalışanları
  • Bölümlere göre maaşların toplamını hesaplama
  • Öğrencileri geçme ve başarısızlığa bölme

Yukarıdaki JavaDoc'ta ayrıntılarla bağlantılı.

Not: Bu soru yazar tarafından kasıtlı olarak yazılır ve cevaplanır ( Kendinden Cevaplanan Sorular ), böylece sık sorulan Kotlin konularına yönelik deyimsel cevaplar SO'da bulunur. Ayrıca Kotlin alfaları için yazılmış ve bugünkü Kotlin için doğru olmayan bazı eski cevapları açıklığa kavuşturmak.


Kullanmak collect(Collectors.toList())ya da benzer bir şey dışında bir seçeneğiniz olmadığı durumlarda , bu sorunla karşılaşabilirsiniz: stackoverflow.com/a/35722167/3679676 (geçici çözümlerle ilgili sorun)
Jayson Minard

Yanıtlar:


257

Kotlin stdlib'de ortalama, sayım, farklı, filtreleme, bulma, gruplama, birleştirme, haritalama, min, maks, bölümleme, dilimleme, sıralama, toplama, diziler arasında / listelerden, listelere / listelerden, haritalardan / haritalara , birlik, ortak-iterasyon, tüm fonksiyonel paradigmalar ve daha fazlası. Böylece, küçük 1 katmanlar oluşturmak için bunları kullanabilirsiniz ve Java 8'in daha karmaşık sözdizimini kullanmaya gerek yoktur.

Yerleşik Java 8 Collectorssınıfında eksik olan tek şeyin özetleme olduğunu düşünüyorum (ancak bu soruya başka bir cevapta basit bir çözüm) .

Her ikisinde de eksik olan bir şey, başka bir Stack Overflow cevabında görülen ve basit bir cevaba sahip olan sayımla toplu işlemdir . Bir başka ilginç durum da Stack Overflow: Kotlin'i kullanarak diziyi üç listeye dökmenin deyimsel yoludur . Ve Stream.collectbaşka bir amaç için benzer bir şey oluşturmak istiyorsanız , bkz. Özel Akış. Kotlin'de toplayın

EDIT 11.08.2017: Kotlin 1.2 M2'de yığınlanmış / pencereli toplama işlemleri eklendi, bkz. Https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/


Zaten orada bulunabilecek yeni işlevler oluşturmadan önce kotlin.collections için API Referansını bir bütün olarak incelemek her zaman iyidir .

Java 8 Stream.collectörneklerinden Kotlin eşdeğerine bazı dönüşümler :

Listede isimleri biriktirme

// Java:  
List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
// Kotlin:
val list = people.map { it.name }  // toList() not needed

Öğeleri dizelere dönüştürün ve virgülle ayırarak birleştirin

// Java:
String joined = things.stream()
                       .map(Object::toString)
                       .collect(Collectors.joining(", "));
// Kotlin:
val joined = things.joinToString(", ")

Çalışan maaşlarının toplamını hesapla

// Java:
int total = employees.stream()
                      .collect(Collectors.summingInt(Employee::getSalary)));
// Kotlin:
val total = employees.sumBy { it.salary }

Bölümlere göre grup çalışanları

// Java:
Map<Department, List<Employee>> byDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));
// Kotlin:
val byDept = employees.groupBy { it.department }

Bölümlere göre maaşların toplamını hesaplama

// Java:
Map<Department, Integer> totalByDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment,
                     Collectors.summingInt(Employee::getSalary)));
// Kotlin:
val totalByDept = employees.groupBy { it.dept }.mapValues { it.value.sumBy { it.salary }}

Öğrencileri geçme ve başarısızlığa bölme

// Java:
Map<Boolean, List<Student>> passingFailing =
     students.stream()
             .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
// Kotlin:
val passingFailing = students.partition { it.grade >= PASS_THRESHOLD }

Erkek üyelerin isimleri

// Java:
List<String> namesOfMaleMembers = roster
    .stream()
    .filter(p -> p.getGender() == Person.Sex.MALE)
    .map(p -> p.getName())
    .collect(Collectors.toList());
// Kotlin:
val namesOfMaleMembers = roster.filter { it.gender == Person.Sex.MALE }.map { it.name }

Listede yer alan üyelerin cinsiyetlerine göre grup adları

// Java:
Map<Person.Sex, List<String>> namesByGender =
      roster.stream().collect(
        Collectors.groupingBy(
            Person::getGender,                      
            Collectors.mapping(
                Person::getName,
                Collectors.toList())));
// Kotlin:
val namesByGender = roster.groupBy { it.gender }.mapValues { it.value.map { it.name } }   

Bir listeyi başka bir listeye filtreleme

// Java:
List<String> filtered = items.stream()
    .filter( item -> item.startsWith("o") )
    .collect(Collectors.toList());
// Kotlin:
val filtered = items.filter { it.startsWith('o') } 

Bir listeye en kısa dizeyi bulma

// Java:
String shortest = items.stream()
    .min(Comparator.comparing(item -> item.length()))
    .get();
// Kotlin:
val shortest = items.minBy { it.length }

Filtre uygulandıktan sonra listedeki öğeleri sayma

// Java:
long count = items.stream().filter( item -> item.startsWith("t")).count();
// Kotlin:
val count = items.filter { it.startsWith('t') }.size
// but better to not filter, but count with a predicate
val count = items.count { it.startsWith('t') }

ve devam ediyor ... Her durumda, taklit etmek için özel bir katlama, azaltma veya başka bir işlevsellik gerekli değildi Stream.collect. Daha fazla kullanım durumunuz varsa, bunları yorumlara ekleyin ve görebilirsiniz!

Tembellik hakkında

Eğer tembel sürecine zinciri istiyorlar, bir dönüştürebileceğiniz Sequencekullanarak asSequence()zinciri önce. Fonksiyon zincirinin sonunda, genellikle bir Sequencede ile sonuçlanırsınız . Sonra kullanabilir toList(), toSet(), toMap()veya başka bir işlev gerçekleştirmek için Sequencesonunda.

// switch to and from lazy
val someList = items.asSequence().filter { ... }.take(10).map { ... }.toList()

// switch to lazy, but sorted() brings us out again at the end
val someList = items.asSequence().filter { ... }.take(10).map { ... }.sorted()

Neden Tür Yok?!?

Kotlin örneklerinin türleri belirtmediğini göreceksiniz. Bunun nedeni Kotlin'in tam tip çıkarımına sahip olması ve derleme zamanında tamamen güvenli olmasıdır. Null olabilecek türlere sahip olduğundan ve korkunç NPE'yi önlemeye yardımcı olabileceğinden Java'dan daha fazlası. Bu Kotlin'de:

val someList = people.filter { it.age <= 30 }.map { it.name }

aynıdır:

val someList: List<String> = people.filter { it.age <= 30 }.map { it.name }

Kotlin bilir için people, ve bu people.ageise Int, bu nedenle filtre ifadesi sadece bir karşılaştırma yapılmasına olanak sağlar Int, ve bu people.namebir olduğunu String, bu nedenle mapaşaması üretir List<String>(salt okunur Listarasında String).

Şimdi, peoplemuhtemelen null, List<People>?o zaman olduğu gibi:

val someList = people?.filter { it.age <= 30 }?.map { it.name }

List<String>?Boş olarak kontrol edilmesi gereken bir değer döndürür ( veya null değerlere ilişkin diğer Kotlin operatörlerinden birini kullanın, null değerlerle başa çıkmak için bu Kotlin deyimsel yoluna ve ayrıca Kotlin'deki null edilebilir veya boş listeyi ele alma deyimine bakın )

Ayrıca bakınız:


Kotlin'de Java8'in parallelStream () işlevine eşdeğer mi?
arnab

Değişmez koleksiyonlar ve Kotlin ile ilgili cevap, paralel için @arnab için aynı cevaptır, diğer kütüphaneler var, onları kullanın: stackoverflow.com/a/34476880/3679676
Jayson Minard

2
@arnab Bu yılın başlarında kullanıma sunulan Java 7/8 özellikleri (özellikle kotlinx-support-jdk8) için Kotlin desteğine bakmak isteyebilirsiniz: tartış.kotlinlang.org/t/jdk7-8-features- in -kotlin-1-0 / 1625
roborative

Bir ifadede 3 farklı "it" referansı kullanmak gerçekten deyimsel mi?
Herman

2
Bu, yukarıdaki örneklerde onları kısa tutuyordum ve sadece gerekirse bir parametre için yerel bir ad sağladım.
Jayson Minard

47

Ek örnekler için Java 8 Stream Tutorial'dan Kotlin'e dönüştürülmüş tüm örnekler . Her örneğin başlığı, kaynak makaleden türetilmiştir:

Akışlar nasıl çalışır?

// Java:
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");

myList.stream()
      .filter(s -> s.startsWith("c"))
      .map(String::toUpperCase)
     .sorted()
     .forEach(System.out::println);

// C1
// C2
// Kotlin:
val list = listOf("a1", "a2", "b1", "c2", "c1")
list.filter { it.startsWith('c') }.map (String::toUpperCase).sorted()
        .forEach (::println)

Farklı Akış Çeşitleri # 1

// Java:
Arrays.asList("a1", "a2", "a3")
    .stream()
    .findFirst()
    .ifPresent(System.out::println);    
// Kotlin:
listOf("a1", "a2", "a3").firstOrNull()?.apply(::println)

veya String'de ifPresent adlı bir uzantı işlevi oluşturun:

// Kotlin:
inline fun String?.ifPresent(thenDo: (String)->Unit) = this?.apply { thenDo(this) }

// now use the new extension function:
listOf("a1", "a2", "a3").firstOrNull().ifPresent(::println)

Ayrıca bakınız: apply()fonksiyon

Ayrıca bkz: Uzantı İşlevleri

Ayrıca bkz: ?.Güvenli Çağrı operatörü ve genel olarak kuralsızlık: Kotlin'de, null değerlerle başa çıkmanın, onları referans göstermenin veya dönüştürmenin deyimsel yolu nedir?

Farklı Akış Türleri # 2

// Java:
Stream.of("a1", "a2", "a3")
    .findFirst()
    .ifPresent(System.out::println);    
// Kotlin:
sequenceOf("a1", "a2", "a3").firstOrNull()?.apply(::println)

Farklı Akımlar # 3

// Java:
IntStream.range(1, 4).forEach(System.out::println);
// Kotlin:  (inclusive range)
(1..3).forEach(::println)

Farklı Akış Çeşitleri # 4

// Java:
Arrays.stream(new int[] {1, 2, 3})
    .map(n -> 2 * n + 1)
    .average()
    .ifPresent(System.out::println); // 5.0    
// Kotlin:
arrayOf(1,2,3).map { 2 * it + 1}.average().apply(::println)

Farklı Akış Türleri # 5

// Java:
Stream.of("a1", "a2", "a3")
    .map(s -> s.substring(1))
    .mapToInt(Integer::parseInt)
    .max()
    .ifPresent(System.out::println);  // 3
// Kotlin:
sequenceOf("a1", "a2", "a3")
    .map { it.substring(1) }
    .map(String::toInt)
    .max().apply(::println)

Farklı Akış Türleri # 6

// Java:
IntStream.range(1, 4)
    .mapToObj(i -> "a" + i)
    .forEach(System.out::println);

// a1
// a2
// a3    
// Kotlin:  (inclusive range)
(1..3).map { "a$it" }.forEach(::println)

Farklı Akış Çeşitleri # 7

// Java:
Stream.of(1.0, 2.0, 3.0)
    .mapToInt(Double::intValue)
    .mapToObj(i -> "a" + i)
    .forEach(System.out::println);

// a1
// a2
// a3
// Kotlin:
sequenceOf(1.0, 2.0, 3.0).map(Double::toInt).map { "a$it" }.forEach(::println)

Sipariş Neden Önemlidir?

Java 8 Stream Eğitimi'nin bu bölümü Kotlin ve Java için aynıdır.

Akışları Yeniden Kullanma

Kotlin'de, koleksiyonun türüne birden fazla kez tüketilip tüketilemeyeceğine bağlıdır. A Sequence, her seferinde yeni bir yineleyici oluşturur ve "yalnızca bir kez kullan" seçeneğini belirtmedikçe, her işlem yapıldığında başlangıç ​​durumuna sıfırlanabilir. Bu nedenle Java 8 akışında aşağıdakiler başarısız olur, ancak Kotlin'de çalışır:

// Java:
Stream<String> stream =
Stream.of("d2", "a2", "b1", "b3", "c").filter(s -> s.startsWith("b"));

stream.anyMatch(s -> true);    // ok
stream.noneMatch(s -> true);   // exception
// Kotlin:  
val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }

stream.forEach(::println) // b1, b2

println("Any B ${stream.any { it.startsWith('b') }}") // Any B true
println("Any C ${stream.any { it.startsWith('c') }}") // Any C false

stream.forEach(::println) // b1, b2

Ve Java'da aynı davranışı elde etmek için:

// Java:
Supplier<Stream<String>> streamSupplier =
    () -> Stream.of("d2", "a2", "b1", "b3", "c")
          .filter(s -> s.startsWith("a"));

streamSupplier.get().anyMatch(s -> true);   // ok
streamSupplier.get().noneMatch(s -> true);  // ok

Bu nedenle Kotlin'de verilerin sağlayıcısı sıfırlanıp yeni bir yineleyici sağlayıp sağlayamayacağına karar verir. Ancak kasıtlı Sequenceolarak bir kerelik yinelemeyi kısıtlamak istiyorsanız, constrainOnce()işlevi Sequenceaşağıdaki gibi kullanabilirsiniz :

val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }
        .constrainOnce()

stream.forEach(::println) // b1, b2
stream.forEach(::println) // Error:java.lang.IllegalStateException: This sequence can be consumed only once. 

Gelişmiş İşlemler

Örnek 5'i toplayın (evet, diğer cevapta bulunanları atladım)

// Java:
String phrase = persons
        .stream()
        .filter(p -> p.age >= 18)
        .map(p -> p.name)
        .collect(Collectors.joining(" and ", "In Germany ", " are of legal age."));

    System.out.println(phrase);
    // In Germany Max and Peter and Pamela are of legal age.    
// Kotlin:
val phrase = persons.filter { it.age >= 18 }.map { it.name }
        .joinToString(" and ", "In Germany ", " are of legal age.")

println(phrase)
// In Germany Max and Peter and Pamela are of legal age.

Bir yan not olarak, Kotlin'de basit veri sınıfları oluşturabilir ve test verilerini aşağıdaki gibi başlatabiliriz:

// Kotlin:
// data class has equals, hashcode, toString, and copy methods automagically
data class Person(val name: String, val age: Int) 

val persons = listOf(Person("Tod", 5), Person("Max", 33), 
                     Person("Frank", 13), Person("Peter", 80),
                     Person("Pamela", 18))

Örnek 6'yı toplayın

// Java:
Map<Integer, String> map = persons
        .stream()
        .collect(Collectors.toMap(
                p -> p.age,
                p -> p.name,
                (name1, name2) -> name1 + ";" + name2));

System.out.println(map);
// {18=Max, 23=Peter;Pamela, 12=David}    

Tamam, Kotlin için daha ilgi çekici bir dava. İlk olarak, Mapbir koleksiyondan / diziden oluşturmanın varyasyonlarını keşfetmek için yanlış yanıtlar :

// Kotlin:
val map1 = persons.map { it.age to it.name }.toMap()
println(map1)
// output: {18=Max, 23=Pamela, 12=David} 
// Result: duplicates overridden, no exception similar to Java 8

val map2 = persons.toMap({ it.age }, { it.name })
println(map2)
// output: {18=Max, 23=Pamela, 12=David} 
// Result: same as above, more verbose, duplicates overridden

val map3 = persons.toMapBy { it.age }
println(map3)
// output: {18=Person(name=Max, age=18), 23=Person(name=Pamela, age=23), 12=Person(name=David, age=12)}
// Result: duplicates overridden again

val map4 = persons.groupBy { it.age }
println(map4)
// output: {18=[Person(name=Max, age=18)], 23=[Person(name=Peter, age=23), Person(name=Pamela, age=23)], 12=[Person(name=David, age=12)]}
// Result: closer, but now have a Map<Int, List<Person>> instead of Map<Int, String>

val map5 = persons.groupBy { it.age }.mapValues { it.value.map { it.name } }
println(map5)
// output: {18=[Max], 23=[Peter, Pamela], 12=[David]}
// Result: closer, but now have a Map<Int, List<String>> instead of Map<Int, String>

Ve şimdi doğru cevap için:

// Kotlin:
val map6 = persons.groupBy { it.age }.mapValues { it.value.joinToString(";") { it.name } }

println(map6)
// output: {18=Max, 23=Peter;Pamela, 12=David}
// Result: YAY!!

Listeleri daraltmak ve örnekten 'e jointToStringtaşınması için bir transformatör sağlamak için eşleşen değerlere katılmamız gerekiyordu .PersonPerson.name

Örnek 7'yi toplayın

Tamam, bu bir gelenek olmadan kolayca yapılabilir Collector, bu yüzden onu Kotlin yolunu çözelim, sonra Kotlin'de Collector.summarizingIntyerel olarak mevcut olmayan benzer bir sürecin nasıl yapılacağını gösteren yeni bir örnek alalım .

// Java:
Collector<Person, StringJoiner, String> personNameCollector =
Collector.of(
        () -> new StringJoiner(" | "),          // supplier
        (j, p) -> j.add(p.name.toUpperCase()),  // accumulator
        (j1, j2) -> j1.merge(j2),               // combiner
        StringJoiner::toString);                // finisher

String names = persons
        .stream()
        .collect(personNameCollector);

System.out.println(names);  // MAX | PETER | PAMELA | DAVID    
// Kotlin:
val names = persons.map { it.name.toUpperCase() }.joinToString(" | ")

Bu önemsiz bir örnek aldı benim hatam değil !!! Tamam, burada summarizingIntKotlin için yeni bir yöntem ve eşleşen bir örnek:

Özetleme Örneği

// Java:
IntSummaryStatistics ageSummary =
    persons.stream()
           .collect(Collectors.summarizingInt(p -> p.age));

System.out.println(ageSummary);
// IntSummaryStatistics{count=4, sum=76, min=12, average=19.000000, max=23}    
// Kotlin:

// something to hold the stats...
data class SummaryStatisticsInt(var count: Int = 0,  
                                var sum: Int = 0, 
                                var min: Int = Int.MAX_VALUE, 
                                var max: Int = Int.MIN_VALUE, 
                                var avg: Double = 0.0) {
    fun accumulate(newInt: Int): SummaryStatisticsInt {
        count++
        sum += newInt
        min = min.coerceAtMost(newInt)
        max = max.coerceAtLeast(newInt)
        avg = sum.toDouble() / count
        return this
    }
}

// Now manually doing a fold, since Stream.collect is really just a fold
val stats = persons.fold(SummaryStatisticsInt()) { stats, person -> stats.accumulate(person.age) }

println(stats)
// output: SummaryStatisticsInt(count=4, sum=76, min=12, max=23, avg=19.0)

Ancak bir uzantı işlevi oluşturmak daha iyidir, 2 aslında Kotlin stdlib'deki stilleri eşleştirmek için:

// Kotlin:
inline fun Collection<Int>.summarizingInt(): SummaryStatisticsInt
        = this.fold(SummaryStatisticsInt()) { stats, num -> stats.accumulate(num) }

inline fun <T: Any> Collection<T>.summarizingInt(transform: (T)->Int): SummaryStatisticsInt =
        this.fold(SummaryStatisticsInt()) { stats, item -> stats.accumulate(transform(item)) }

Artık yeni summarizingIntişlevleri kullanmanın iki yolu var :

val stats2 = persons.map { it.age }.summarizingInt()

// or

val stats3 = persons.summarizingInt { it.age }

Ve bunların hepsi aynı sonuçları veriyor. Bu eklentiyi, Sequenceuygun ilkel türler üzerinde ve bunlarda çalışmak için de oluşturabiliriz .

Eğlenmek için Java JDK kodunu ve bu özetin uygulanması için gereken Kotlin özel kodunu karşılaştırın .


5. akışta, bir yerine iki harita kullanmak için bir artı yoktur .map { it.substring(1).toInt() }: iyi bildiğiniz gibi, türün kotlin gücünden biridir.
Michele d'Amico

doğru, ama hiçbir dezavantajı da yok (karşılaştırılabilirlik için onları ayrı tuttu)
Jayson Minard

Ancak Java kodu kolayca paralel hale getirilebilir, bu nedenle çoğu durumda Kotlin'den Java akış kodunu çağırmak daha iyi olur.
Howard Lovatt

@HowardLovatt, özellikle zaten bir iş parçacığı havuzunda olduğunuz ağır eşzamanlı ortamlarda, paralel yolun gitmediği birçok durum vardır. Bahse girerim ortalama kullanım durumu paralel DEĞİLDİR ve nadir görülen bir durumdur. Ancak elbette, her zaman uygun gördüğünüz gibi Java sınıflarını kullanma seçeneğiniz vardır ve bunların hiçbiri gerçekten bu sorunun ve cevabın amacı değildi.
Jayson Minard

3

Aramaktan kaçınmanın zor olduğu bazı durumlar vardır collect(Collectors.toList()). Bu durumlarda, aşağıdaki gibi uzantı işlevlerini kullanarak bir Kotlin eşdeğerine daha hızlı bir şekilde geçiş yapabilirsiniz:

fun <T: Any> Stream<T>.toList(): List<T> = this.collect(Collectors.toList<T>())
fun <T: Any> Stream<T>.asSequence(): Sequence<T> = this.iterator().asSequence()

Sonra basitçe yapabilirsiniz stream.toList()veya stream.asSequence()Kotlin API geri hareket ettirmek için. Gibi bir vaka Files.list(path)sizi Streamistemediğiniz bir zamana zorlar ve bu uzantılar standart koleksiyonlara ve Kotlin API'sine geri dönmenize yardımcı olabilir.


2

Tembellik hakkında daha fazla bilgi

Jayson tarafından verilen "Bölümlere göre maaş hesaplaması" için örnek çözümü ele alalım:

val totalByDept = employees.groupBy { it.dept }.mapValues { it.value.sumBy { it.salary }}

Bunu tembel hale getirmek (yani groupByadımda bir ara harita oluşturmaktan kaçınmak ) için kullanmak mümkün değildir asSequence(). Bunun yerine, biz kullanmalıdır groupingByve foldişletim:

val totalByDept = employees.groupingBy { it.dept }.fold(0) { acc, e -> acc + e.salary }

Bazı kişiler için bu daha okunabilir olabilir, çünkü harita girişleriyle uğraşmıyorsunuz: it.valueçözümdeki kısım ilk başta benim için kafa karıştırıyordu.

Bu yaygın bir durum olduğundan ve foldher seferinde yazmamayı tercih ettiğimizden , aşağıdaki konularda genel bir sumByişlev sağlamak daha iyi olabilir Grouping:

public inline fun <T, K> Grouping<T, K>.sumBy(
        selector: (T) -> Int
): Map<K, Int> = 
        fold(0) { acc, element -> acc + selector(element) }

böylece şunu yazabiliriz:

val totalByDept = employees.groupingBy { it.dept }.sumBy { it.salary }
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.