जावा 8 Stream.collect समकक्ष मानक कोटलिन लाइब्रेरी में क्या उपलब्ध हैं?


181

जावा 8 में, Stream.collectसंग्रह पर एकत्रीकरण की अनुमति देता है। कोटलिन में, यह उसी तरह से मौजूद नहीं है, जैसा कि स्टडीलिब में विस्तार कार्यों के संग्रह के अलावा अन्य हो सकता है। लेकिन यह स्पष्ट नहीं है कि विभिन्न उपयोग मामलों के लिए समतुल्य क्या हैं।

उदाहरण के लिए, JavaDocCollectors के शीर्ष पर Java 8 के लिए लिखे गए उदाहरण हैं, और उन्हें कॉलिन में पोर्ट करते समय आप एक अलग JDK संस्करण पर जावा 8 कक्षाओं का उपयोग नहीं कर सकते, इसलिए संभव है कि उन्हें अलग तरह से लिखा जाए।

कोटलिन संग्रह के उदाहरणों को ऑनलाइन दिखाने वाले संसाधनों के संदर्भ में, वे आम तौर पर तुच्छ हैं और वास्तव में समान उपयोग के मामलों की तुलना नहीं करते हैं। ऐसे अच्छे उदाहरण क्या हैं जो वास्तव में जावा 8 के दस्तावेज जैसे मामलों से मेल खाते हैं Stream.collect? सूची वहाँ है:

  • सूची में नाम संचित करें
  • ट्रीसेट में नाम संचित करें
  • तत्वों को स्ट्रिंग्स में परिवर्तित करें और उन्हें अलग करें, अल्पविराम द्वारा अलग किया गया
  • कर्मचारी के वेतन की गणना योग
  • विभाग द्वारा समूह कर्मचारी
  • विभाग द्वारा वेतन की गणना
  • छात्रों को उत्तीर्ण और अनुत्तीर्ण करने में विभाजन

ऊपर दिए गए JavaDoc में विवरण के साथ।

नोट: यह प्रश्न जानबूझकर लिखा गया है और लेखक द्वारा ( स्व-उत्तर वाले प्रश्न ) उत्तर दिया गया है , ताकि आमतौर पर पूछे जाने वाले कोटलिन विषयों के मुहावरेदार उत्तर एसओ में मौजूद हों। कोटलिन के अल्फ़ाज़ों के लिए लिखे गए कुछ वास्तव में पुराने उत्तरों को स्पष्ट करने के लिए, जो वर्तमान के कोटलिन के लिए सटीक नहीं हैं।


ऐसे मामलों में जहां आपके पास उपयोग करने के लिए collect(Collectors.toList())या इसी तरह का कोई विकल्प नहीं है , आप इस मुद्दे को मार सकते हैं: stackoverflow.com/a/35722167/3679676 (समस्या, वर्कअराउंड के साथ)
जेसन माइनर

जवाबों:


257

कोटलिन stdlib में फ़ंक्शंस हैं, औसत, गिनती, अलग-अलग, फ़िल्टरिंग, खोज, समूहन, जुड़ना, मैपिंग, न्यूनतम, अधिकतम, विभाजन, टुकड़ा करना, छांटना, समेटना, / से, सरणियों से, सूची से / से, नक्शे से / से। , संघ, सह-पुनरावृत्ति, सभी कार्यात्मक प्रतिमान, और बहुत कुछ। तो आप उन छोटे 1-लाइनरों को बनाने के लिए उपयोग कर सकते हैं और जावा 8 के अधिक जटिल सिंटैक्स का उपयोग करने की आवश्यकता नहीं है।

मुझे लगता है कि अंतर्निहित जावा 8 Collectorsकक्षा से केवल एक चीज गायब है संक्षेपण है (लेकिन इस प्रश्न का एक अन्य उत्तर में एक सरल समाधान है)

दोनों में से एक चीज़ गायब है, जो गिनती से बैचिंग है, जो एक और स्टैक ओवरफ्लो उत्तर में दिखाई देती है और इसका एक सरल उत्तर भी है। एक और दिलचस्प मामला यह है कि स्टैक ओवरफ्लो से एक भी है: कोटलिन का उपयोग करके तीन सूचियों में अनुक्रम को फैलाने का अज्ञात तरीका । और यदि आप Stream.collectकिसी अन्य उद्देश्य के लिए कुछ बनाना चाहते हैं , तो कोटलिन में कस्टम स्ट्रीम देखें

EDIT 11.08.2017: कोटेड / विंडो संग्रह संचालन को कोटलिन 1.2 M2 में जोड़ा गया, देखें https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/


नए फ़ंक्शन बनाने से पहले kotlin.collections के लिए API संदर्भ का पता लगाना हमेशा अच्छा होता है जो पहले से ही वहां मौजूद हो सकते हैं।

Stream.collectकोटलिन में जावा 8 उदाहरण के समकक्ष कुछ रूपांतरण यहां दिए गए हैं :

सूची में नाम संचित करें

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

तत्वों को स्ट्रिंग्स में परिवर्तित करें और उन्हें अलग करें, अल्पविराम द्वारा अलग किया गया

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

कर्मचारी के वेतन की गणना योग

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

विभाग द्वारा समूह कर्मचारी

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

विभाग द्वारा वेतन की गणना

// 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 }}

छात्रों को उत्तीर्ण और अनुत्तीर्ण करने में विभाजन

// 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 }

पुरुष सदस्यों के नाम

// 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 }

लिंग द्वारा रोस्टर में सदस्यों के समूह के नाम

// 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 } }   

एक सूची को दूसरी सूची में फ़िल्टर करें

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

सबसे छोटी स्ट्रिंग एक सूची ढूँढना

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

फ़िल्टर लागू होने के बाद किसी सूची में आइटम की गिनती करना

// 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') }

और इस पर चला जाता है ... सभी मामलों में, नकल करने के लिए कोई विशेष गुना, कम, या अन्य कार्यक्षमता की आवश्यकता नहीं थी Stream.collect। यदि आपके पास आगे उपयोग के मामले हैं, तो उन्हें टिप्पणियों में जोड़ें और हम देख सकते हैं!

आलस्य के बारे में

यदि आप एक श्रृंखला को आलसी करना चाहते हैं, तो आप श्रृंखला से पहले Sequenceउपयोग करके परिवर्तित कर सकते हैं asSequence()। कार्यों की श्रृंखला के अंत में, आप आमतौर पर एक के Sequenceरूप में अच्छी तरह से समाप्त करते हैं । तो फिर तुम उपयोग कर सकते हैं toList(), toSet(), toMap()या कुछ अन्य समारोह अमल में लाना करने के लिए Sequenceअंत में।

// 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()

कोई प्रकार क्यों नहीं हैं?

आप ध्यान देंगे कोटलिन के उदाहरण प्रकारों को निर्दिष्ट नहीं करते हैं। इसका कारण यह है कि कोटलिन में पूर्ण प्रकार का अनुमान है और संकलन के समय पूरी तरह से सुरक्षित है। जावा से अधिक इसलिए क्योंकि इसमें अशक्त प्रकार भी हैं और यह खतरनाक NPE को रोकने में मदद कर सकता है। तो कोटलिन में यह:

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

के समान है:

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

क्योंकि Kotlin जानता है क्या peopleहै, और कहा कि people.ageहै Intइसलिए फिल्टर अभिव्यक्ति केवल एक की तुलना की अनुमति देता है Int, और कहा कि people.nameएक है Stringइसलिए mapकदम एक का उत्पादन List<String>(केवल पढ़ने Listके String)।

अब, अगर peopleथे संभवतः null, के रूप में में एक List<People>?तो:

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

रिटर्न एक List<String>?है कि (शून्य जाँच करने की आवश्यकता होगी या देखते हैं कि यह नल मूल्यों के लिए अन्य Kotlin ऑपरेटरों में से एक का उपयोग करें, नल मूल्यों से निपटने के लिए Kotlin मुहावरेदार तरीका है और यह भी Kotlin में नल या रिक्त सूची से निपटने का मुहावरेदार रास्ता )

यह सभी देखें:


क्या कोटलिन में जावा 8 के समानांतर स्ट्रीम्स () के बराबर है?
अर्नब

अपरिवर्तनीय संग्रह और Kotlin के बारे में जवाब @arnab यहां समानांतर के लिए के लिए एक ही जवाब है, अन्य पुस्तकालयों मौजूद हैं, उनका इस्तेमाल: stackoverflow.com/a/34476880/3679676
जेसन Minard

2
@arnab आप जावा 7/8 सुविधाओं के लिए Kotlin समर्थन को देखने के लिए (विशेष रूप से, kotlinx-support-jdk8 में) है कि इस साल के उपलब्ध कराया गया था चाहते हो सकता है: discuss.kotlinlang.org/t/jdk7-8-features-in -कोटलिन-1-0 / 1625
भड़काऊ

क्या एक बयान में 3 अलग "यह" संदर्भों का उपयोग करना वास्तव में मुहावरेदार है?
हरमन

2
यह एक प्राथमिकता है, ऊपर के नमूनों में मैं उन्हें कम रख रहा था और यदि आवश्यक हो तो एक पैरामीटर के लिए केवल एक स्थानीय नाम प्रदान कर रहा था।
जैसन मिनार्ड

47

अतिरिक्त उदाहरणों के लिए, यहाँ जावा 8 स्ट्रीम ट्यूटोरियल से सभी नमूने कोटलिन में बदल दिए गए हैं। प्रत्येक उदाहरण का शीर्षक, स्रोत लेख से लिया गया है:

धाराएँ कैसे काम करती हैं

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

धाराओं # 1 के विभिन्न प्रकार

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

या, स्ट्रिंग पर एक एक्सटेंशन फ़ंक्शन बनाएं जिसे ifresent कहा जाता है:

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

यह भी देखें: apply()समारोह

इन्हें भी देखें: एक्सटेंशन फ़ंक्शंस

यह भी देखें: ?.सुरक्षित कॉल ऑपरेटर , और सामान्य अशक्तता में: कोटलीन में, अशक्त मूल्यों से निपटने, उन्हें संदर्भित करने या परिवर्तित करने के लिए मुहावरेदार तरीका क्या है

धाराओं # 2 के विभिन्न प्रकार

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

धाराओं # 3 के विभिन्न प्रकार

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

धाराओं # 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)

धाराओं # 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)

धाराओं के विभिन्न प्रकार # 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)

धाराओं के विभिन्न प्रकार # 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)

ऑर्डर मैटर्स क्यों?

जावा 8 स्ट्रीम ट्यूटोरियल का यह भाग कोटलिन और जावा के लिए समान है।

पुन: उपयोग की धाराएँ

कोटलिन में, यह संग्रह के प्रकार पर निर्भर करता है कि क्या इसका एक से अधिक बार सेवन किया जा सकता है। एक Sequenceएक नया इटरेटर हर बार उत्पन्न करता है, और हर बार यह पर काम किया जाता है, जब तक यह शुरू "उपयोग केवल एक बार" का दावा है उसे रीसेट कर सकते। इसलिए जब जावा 8 स्ट्रीम में निम्नलिखित विफल रहता है, लेकिन कोटलिन में काम करता है:

// 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

और जावा में समान व्यवहार प्राप्त करने के लिए:

// 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

इसलिए कोटलिन में डेटा का प्रदाता यह तय करता है कि क्या यह वापस रीसेट हो सकता है और नया पुनरावृत्त प्रदान कर सकता है या नहीं। लेकिन अगर आप जानबूझकर एक Sequenceसे अधिक बार चलना चाहते हैं, तो आप निम्नानुसार constrainOnce()फ़ंक्शन का उपयोग कर सकते हैं Sequence:

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. 

उन्नत संचालन

उदाहरण # 5 लीजिए (हां, मैंने उन लोगों को पहले ही जवाब में छोड़ दिया)

// 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.

और एक साइड नोट के रूप में, कोटलिन में हम सरल डेटा क्लासेस बना सकते हैं और परीक्षण डेटा को निम्न प्रकार से लिख सकते हैं :

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

उदाहरण # 6 लीजिए

// 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}    

ठीक है, कोटलिन के लिए यहां एक अधिक रुचि वाला मामला। Mapसंग्रह / अनुक्रम से बनाने की विविधताओं का पता लगाने के लिए पहले गलत उत्तर :

// 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>

और अब सही उत्तर के लिए:

// 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!!

हमें केवल सूचियों को संक्षिप्त करने और उदाहरण के लिए ट्रांसफार्मर jointToStringसे स्थानांतरित करने के लिए एक ट्रांसफार्मर प्रदान करने के लिए मिलान मूल्यों में शामिल होने की आवश्यकता थी ।PersonPerson.name

उदाहरण # 7 लीजिए

ठीक है, यह आसानी से एक रिवाज के बिना किया जा सकता है Collector, तो चलिए इसे कोटलिन तरीके से हल करते हैं, फिर एक नया उदाहरण देते हैं जो दिखाता है कि इसी तरह की प्रक्रिया कैसे करें Collector.summarizingIntजिसके लिए कोटलिन में मूल रूप से मौजूद नहीं है।

// 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(" | ")

यह मेरी गलती नहीं है कि उन्होंने एक तुच्छ उदाहरण चुना !!! ठीक है, यहाँ summarizingIntकोटलिन और एक मिलान नमूने के लिए एक नई विधि है:

SummarizingInt उदाहरण

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

लेकिन विस्तार समारोह बनाने के लिए बेहतर है, 2 वास्तव में कोटलिन स्टडलिब में शैलियों का मिलान करें:

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

अब आपके पास नए summarizingIntकार्यों का उपयोग करने के दो तरीके हैं :

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

// or

val stats3 = persons.summarizingInt { it.age }

और ये सभी समान परिणाम देते हैं। हम इस विस्तार को Sequenceउचित आदिम प्रकारों पर काम करने के लिए भी बना सकते हैं ।

मज़े के लिए, इस संक्षेप को लागू करने के लिए आवश्यक जावा JDK कोड बनाम कोटलिन कस्टम कोड की तुलना करें


धारा 5 में एक के बजाय दो मानचित्रों का उपयोग करने के लिए कोई प्लस नहीं है .map { it.substring(1).toInt() }: जैसा कि आप जानते हैं कि अच्छी तरह से अनुमान लगाया गया है कि कोटलिन शक्ति में से एक है।
मिशेल

सच है, लेकिन कोई नकारात्मक पहलू भी नहीं है (तुलना के लिए मैंने उन्हें अलग रखा)
जैसन मिनार्ड

लेकिन जावा कोड आसानी से समानांतर बनाया जा सकता है, इसलिए कई मामलों में आप कोटलिन से जावा स्ट्रीम कोड को कॉल करना बेहतर होगा।
हावर्ड लोवेट

@ हॉवर्डलोवेट ऐसे कई मामले हैं जहां समानांतर जाने का रास्ता नहीं है, विशेष रूप से भारी समवर्ती वातावरण में जहां आप पहले से ही एक थ्रेड पूल में हैं। मैं शर्त लगा रहा हूं कि औसत उपयोग का मामला समानांतर नहीं है, और यह दुर्लभ मामला है। लेकिन निश्चित रूप से, आपके पास हमेशा जावा वर्गों का उपयोग करने का विकल्प होता है जैसा कि आप फिट देखते हैं, और इनमें से कोई भी वास्तव में इस प्रश्न और उत्तर का उद्देश्य नहीं था।
जैसन मिनार्ड

3

कुछ मामले ऐसे होते हैं, जिनमें कॉलिंग collect(Collectors.toList())या समान से बचना मुश्किल होता है । उन मामलों में, आप विस्तार कार्यों का उपयोग करते हुए कोटलिन के समकक्ष अधिक तेज़ी से बदल सकते हैं:

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

तब आप बस stream.toList()या stream.asSequence()कोटलिन एपीआई में वापस जा सकते हैं । जब आप ऐसा नहीं चाहते हैं तो एक केस Files.list(path)आपको मजबूर Streamकरता है, और ये एक्सटेंशन आपको मानक संग्रह और कोटलिन एपीआई में वापस शिफ्ट करने में मदद कर सकते हैं।


2

आलस्य पर अधिक

आइए जैसन द्वारा दिए गए "विभाग द्वारा वेतन की गणना राशि" के लिए उदाहरण का हल निकालें:

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

इस आलसी को बनाने के लिए (यानी groupByकदम में एक मध्यवर्ती मानचित्र बनाने से बचें ), इसका उपयोग करना संभव नहीं है asSequence()। इसके बजाय, हमें उपयोग groupingByऔर foldसंचालन करना चाहिए :

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

कुछ लोगों के लिए यह और भी पठनीय हो सकता है, क्योंकि आप मानचित्र प्रविष्टियों के साथ काम नहीं कर रहे हैं: it.valueसमाधान में हिस्सा मेरे लिए पहले भी भ्रमित था।

चूंकि यह एक सामान्य मामला है और हम foldहर बार इसे नहीं लिखना चाहेंगे , इसलिए बेहतर होगा कि आप केवल एक सामान्य sumByकार्य प्रदान करें Grouping:

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

ताकि हम बस लिख सकें:

val totalByDept = employees.groupingBy { it.dept }.sumBy { it.salary }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.