कोटलिन में गुना और कम के बीच बुनियादी अंतर क्या है? कब कौन सा उपयोग करें?


132

मैं इस दोनों कार्यों से fold()और reduce()कोटलिन में बहुत भ्रमित हूं , क्या कोई मुझे एक ठोस उदाहरण दे सकता है जो दोनों को अलग करता है?



4
इस विषय की गहन मौलिक चर्चा के लिए इस पर एक नज़र डालें
घोस्टकट

2
@ LunarWatcher, मैंने उन डॉक्स को देखा, लेकिन नहीं मिल रहा है, यह y पोस्ट किया गया प्रश्न है, क्या आप उदाहरण दे सकते हैं?
तपनह

1
@MattKlein किया
जेसन Minard

जवाबों:


281

fold एक प्रारंभिक मूल्य लेता है, और आपके द्वारा पास किए गए लैम्ब्डा का पहला आह्वान उस प्रारंभिक मूल्य और पैरामीटर के संग्रह का पहला तत्व प्राप्त करेगा।

उदाहरण के लिए, निम्न कोड लें जो पूर्णांकों की सूची के योग की गणना करता है:

listOf(1, 2, 3).fold(0) { sum, element -> sum + element }

लैम्ब्डा के लिए पहली कॉल मापदंडों 0और के साथ होगी 1

यदि आपको अपने ऑपरेशन के लिए किसी प्रकार का डिफ़ॉल्ट मान या पैरामीटर प्रदान करना है, तो प्रारंभिक मूल्य में पास होने की क्षमता होना उपयोगी है। उदाहरण के लिए, यदि आप किसी सूची के अंदर अधिकतम मूल्य की तलाश कर रहे थे, लेकिन किसी कारण से कम से कम 10 पर वापस जाना चाहते हैं, तो आप निम्नलिखित कार्य कर सकते हैं:

listOf(1, 6, 4).fold(10) { max, element ->
    if (element > max) element else max
}

reduceएक प्रारंभिक मूल्य नहीं लेता है, लेकिन इसके बजाय संचयकर्ता के रूप में संग्रह के पहले तत्व के साथ शुरू होता है ( sumनिम्नलिखित उदाहरण में कहा जाता है)।

उदाहरण के लिए, आइए फिर से पूर्णांक का योग करें:

listOf(1, 2, 3).reduce { sum, element -> sum + element }

यहां लंबोदर का पहला कॉल मापदंडों 1और के साथ होगा 2

आप उपयोग कर सकते हैं reduceजब आपका ऑपरेशन उस संग्रह के अलावा किसी भी मान पर निर्भर नहीं करता है जिसे आप इसे लागू कर रहे हैं।


47
अच्छे खर्च! मैं यह भी कहूंगा, कि खाली संग्रह को कम नहीं किया जा सकता है, लेकिन तह किया जा सकता है।
Miha_x64

देखें, कोटलिन में बहुत शुरुआती स्तर पर, आपके द्वारा दिए गए पहले उदाहरण से आप इसे कुछ चरणों और अंतिम उत्तर के साथ समझा सकते हैं? बहुत मदद मिलेगी
तपनह

3
@ तपनएचपी emptyList<Int>().reduce { acc, s -> acc + s }एक अपवाद का उत्पादन करेगा, लेकिन emptyList<Int>().fold(0) { acc, s -> acc + s }ठीक है।
Miha_x64

31
कम करना भी सूची सदस्यों के समान लंबोदर की वापसी को मजबूर करता है, जो कि तह के साथ सच नहीं है। यह सूची का पहला तत्व बनाने का एक महत्वपूर्ण परिणाम है, संचायक का प्रारंभिक मूल्य।
andresp

4
@ शेडोंग: पूर्णता के लिए एक नोट के रूप में: यह एक ही प्रकार का होना जरूरी नहीं है । सूची के सदस्य भी संचायक का एक उपप्रकार हो सकते हैं: यह काम करता है listOf<Int>(1, 2).reduce { acc: Number, i: Int -> acc.toLong() + i }(सूची-प्रकार इंट है जबकि संचायक प्रकार को संख्या के रूप में घोषित किया जाता है और वास्तव में एक लंबा होता है)
बोरिस

11

प्रमुख कार्यात्मक अंतर जिसे मैं बाहर कॉल करूंगा (जो अन्य उत्तर पर टिप्पणियों में उल्लिखित है, लेकिन समझना मुश्किल हो सकता है) यह है कि एक खाली संग्रह पर प्रदर्शन किए जाने पर एक reduce अपवाद फेंक दिया जाएगा

listOf<Int>().reduce { x, y -> x + y }
// java.lang.UnsupportedOperationException: Empty collection can't be reduced.

इसका कारण यह है कि .reduce"कोई डेटा नहीं" की स्थिति में वापस जाने के लिए क्या मूल्य है।

इसके साथ विरोधाभास करें .fold, जिसके लिए आपको "प्रारंभिक मूल्य" प्रदान करना होगा, जो खाली संग्रह की स्थिति में डिफ़ॉल्ट मान होगा:

val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)

इसलिए, भले ही आप अपने संग्रह को किसी भिन्न (गैर-संबंधित) प्रकार के एकल तत्व तक सीमित नहीं करना चाहते (जो केवल .foldआपको करने देगा), यदि आपका प्रारंभिक संग्रह खाली हो सकता है, तो आपको या तो अपने संग्रह की जांच करनी चाहिए आकार पहले और फिर .reduce, या बस उपयोग करें.fold

val collection: List<Int> = // collection of unknown size

val result1 = if (collection.isEmpty()) 0
              else collection.reduce { x, y -> x + y }

val result2 = collection.fold(0) { x, y -> x + y }

assertEquals(result1, result2)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.