2016-12-20 11 views
11

जावा 8 में स्कैला के महान foldLeft के बराबर क्या है?जावा में स्कैला के फोल्ड लाइफ के समतुल्य 8

मुझे यह सोचने का लुत्फ था कि यह reduce था, लेकिन इसे कम करने के लिए समान प्रकार के कुछ प्रकार को वापस करना होगा।

उदाहरण: new StringBuilder("")

इस प्रकार, किसी को भी मुझे foldLeft के समुचित बराबर को इंगित कर सकता है/मेरे कोड को ठीक:

import java.util.List; 

public class Foo { 

    // this method works pretty well 
    public int sum(List<Integer> numbers) { 
     return numbers.stream() 
         .reduce(0, (acc, n) -> (acc + n)); 
    } 

    // this method makes the file not compile 
    public String concatenate(List<Character> chars) { 
     return chars.stream() 
        .reduce(new StringBuilder(""), (acc, c) -> acc.append(c)).toString(); 
    } 
} 

उपरोक्त कोड में समस्या acc umulator है?

+2

एफवाईआई: भाषा का नाम "स्कैला" है, न कि "स्कैला"। (मेरा मानना ​​है कि "स्कैला" नामक एक अलग भाषा है, जो संभवतः आपका मतलब नहीं है।) –

+0

संबंधित http://stackoverflow.com/questions/30736587/builder-pattern-with-a-java-8- स्ट्रीम – Tunaki

उत्तर

6

अद्यतन:

public static String concatenate(List<Character> chars) { 
     return chars 
       .stream() 
       .reduce(new StringBuilder(), 
           StringBuilder::append, 
           StringBuilder::append).toString(); 
    } 

यह का उपयोग करता है निम्नलिखित reduce method:

अपने कोड प्राप्त करने के लिए तय की प्रारंभिक प्रयास है

<U> U reduce(U identity, 
       BiFunction<U, ? super T, U> accumulator, 
       BinaryOperator<U> combiner); 

यह भ्रामक लग सकता है, लेकिन अगर आप देखो जावाडॉक्स में एक अच्छी व्याख्या है जो आपको विवरणों को तुरंत समझने में मदद कर सकती है। कमी का अनुसरण कोड के बराबर है:

U result = identity; 
for (T element : this stream) 
    result = accumulator.apply(result, element) 
return result; 

एक अधिक गहराई से स्पष्टीकरण के लिए जाँच कृपया this source

यह प्रयोग, क्योंकि यह जो कहा गया है कि संचायक होना चाहिए एक साहचर्य, एक परिणाम के में एक अतिरिक्त तत्व शामिल करने के लिए गैर दखल दे, राज्यविहीन समारोह को कम के अनुबंध का उल्लंघन करती है, हालांकि सही नहीं है। दूसरे शब्दों में, चूंकि पहचान उत्परिवर्तनीय है, परिणाम समानांतर निष्पादन के मामले में तोड़ा जाएगा।

के रूप में एक सही विकल्प नीचे टिप्पणी में बताया कमी उपयोग कर रहा है इस प्रकार है:

return chars.stream().collect(
    StringBuilder::new, 
    StringBuilder::append, 
    StringBuilder::append).toString(); 

आपूर्तिकर्ता StringBuilder::new पुन: प्रयोज्य कंटेनर जो बाद में जोड़ा जाएगा बनाने के लिए इस्तेमाल किया जाएगा।

+6

अन्य उत्तर के समान ही: * इस तरह से 'कम करें' का उपयोग न करें। कार्यों को उनके पैरामीटर को संशोधित करने की अनुमति नहीं है * नहीं। सही उपयोग '.collect (स्ट्रिंगबिल्डर :: नया, स्ट्रिंगबिल्डर :: संलग्न, स्ट्रिंगबिल्डर :: संलग्न) है। देखें [उत्परिवर्तनीय कमी] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#MutableReduction)। – Holger

+0

@ होल्गर: धन्यवाद, यह सच है। जवाब अपडेट किया गया है। –

+3

यह दक्षता के बारे में नहीं है, यह शुद्धता के बारे में है। 'कम करें' का उपयोग इस तरह से अनुबंध का उल्लंघन करता है और इसे तोड़ दिया जाना चाहिए, भले ही यह कुछ परिस्थितियों में इच्छित चीज कर सके। सबसे विशेष रूप से, यह समानांतर धारा का उपयोग करते समय निश्चित रूप से टूट जाएगा। – Holger

7

जिस विधि को आप ढूंढ रहे हैं वह java.util.Stream.reduce है, विशेष रूप से तीन पैरामीटर, पहचान, संचयक, और बाइनरी फ़ंक्शन के साथ ओवरलोड। यह स्कैला के foldLeft के बराबर सही है।

हालांकि, अगर आप नहीं जावा के reduce कि जिस तरह से उपयोग करने की अनुमति नहीं है, और यह भी नहीं स्काला के foldLeft उस बात के लिए। इसके बजाय collect का उपयोग करें।

+3

जबकि मुझे आपका जवाब पसंद है, "आपको अनुमति नहीं है" थोड़ा गलत लगता है। क्या आप इसे दूसरे शब्दों में कह सकते हैं? –

+2

यह एक प्रकार की त्रुटि होगी यदि जावा की टाइप सिस्टम उस बाधा को व्यक्त करने के लिए पर्याप्त अभिव्यक्तिपूर्ण थी। लेकिन ऐसा नहीं है, बाधा केवल जावा डॉक्स में उल्लिखित है। जावाडॉक्स का कहना है कि आपको किस प्रकार की ऑब्जेक्ट्स पास करने की अनुमति है, और ओपी पास की ऑब्जेक्ट्स उन बाधाओं को पूरा नहीं करती हैं, उन्हें अहंकार को 'कम करने' की अनुमति नहीं है। आप और कैसे वाक्यांश करेंगे? –

+2

ठीक है, इस प्रकार पर कोई प्रतिबंध नहीं है, केवल आप वस्तुओं का उपयोग कैसे करते हैं। यदि आप '(ए, बी) -> नया स्ट्रिंगबिल्डर() जोड़ते हैं तो accumulator और combiner कार्यों का उपयोग करें। (ए) .append (बी) ', यह एक कानूनी उपयोग होगा, हालांकि' संग्रह' की तुलना में यह बहुत कुशल नहीं है उपाय। – Holger

7

जावा 8 के स्ट्रीम एपीआई में foldLeft के बराबर नहीं है। जैसा कि अन्य ने नोट किया, करीब आता है, लेकिन यह foldLeft के बराबर नहीं है क्योंकि इसके परिणामस्वरूप B को स्वयं के साथ गठबंधन करने और सहयोगी होने की आवश्यकता होती है (अन्य शब्दों में, मोनोइड-जैसी हो), एक ऐसी संपत्ति जो हर प्रकार की नहीं है।add Stream.foldLeft() terminal operation

देखने के लिए क्यों कम करने से काम नहीं चलेगा, दी गई संख्या के साथ शुरू निम्नलिखित कोड है, जहां आप अंकगणितीय आपरेशनों की एक श्रृंखला पर अमल करने का इरादा पर विचार करें::

वहाँ भी इस के लिए एक वृद्धि अनुरोध है

val arithOps = List(('+', 1), ('*', 4), ('-', 2), ('/', 5)) 
val fun: (Int, (Char, Int)) => Int = { 
    case (x, ('+', y)) => x + y 
    case (x, ('-', y)) => x - y 
    case (x, ('*', y)) => x * y 
    case (x, ('/', y)) => x/y 
} 
val number = 2 
arithOps.foldLeft(number)(fun) // ((2 + 1) * 4 - 2)/5 

यदि आपने reduce(2, fun, combine) लिखने का प्रयास किया है, तो आप किस संयोजन को पार कर सकते हैं जो दो संख्याओं को जोड़ती है? दो संख्याओं को एक साथ जोड़कर स्पष्ट रूप से इसे हल नहीं किया जाता है। इसके अलावा, मूल्य 2 स्पष्ट रूप से पहचान तत्व नहीं है।

ध्यान दें कि अनुक्रमिक निष्पादन की आवश्यकता वाले किसी भी ऑपरेशन को reduce के संदर्भ में व्यक्त किया जा सकता है। foldLeft वास्तव में reduce से अधिक सामान्य है: आप को foldLeft के साथ कार्यान्वित कर सकते हैं लेकिन आप foldLeftreduce के साथ लागू नहीं कर सकते हैं।

संबंधित मुद्दे