2012-10-28 15 views
8

मुझे एक इटेबल [या तो [थ्रोबल, स्ट्रिंग]] को किसी भी [थ्रोबल, इटेबल [स्ट्रिंग]] को कम करने की आवश्यकता है। मुझे नहीं पता कि यह ऑपरेशन बहुत आम है या नहीं, Iterable विशेषता पर कुछ भी नहीं मिला है। इसलिए मैंने यह फ़ंक्शन लिखा है:इटरबल [या तो [ए, बी]] को कम करने के लिए [ए, इटेबल [बी]]

def reduce[A, B](xs: Iterable[Either[A, B]]): Either[A, Iterable[B]] = 
    xs.collectFirst { 
    case Left(x) => x 
    } match { 
    case Some(x) => Left(x) 
    case None => Right(xs.collect{case Right(y)=> y}) 
    } 

क्या कोई मुझे बेहतर तरीका खोजने में मदद कर सकता है यदि यह ऐसा नहीं है?

+0

परिवर्तन हासिल करना चाहते हैं थोड़ा अस्पष्ट है। आपकी इनपुट सूची में 'राइट [स्ट्रिंग]' के आधा और विभिन्न और विषम 'बाएं [अपवाद] के आधे उदाहरण हैं। आप इसे किसी एक अपवाद या तारों की सूची में कम करना चाहते हैं। यदि उदाहरण थे तो कौन सा अपवाद लिया जाना चाहिए इनपुट में दस अलग? –

+0

आप सही हैं। मैं केवल पहला अपवाद (या कोई वाम मूल्य) पर विचार करना चाहता हूं, यह अन्य को छिपाएगा लेकिन यह मेरे उपयोग के मामले के लिए स्वीकार्य है। –

+0

यह http://stackoverflow.com/questions/7230999/how-to-reduce-a-seqeithera-b-to-a-eitherseqa-seqb का डुप्लिकेट है। – ziggystar

उत्तर

11

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

val xs: List[Either[String, Int]] = List(Right(1), Right(2)) 
val ys: List[Either[String, Int]] = List(Right(1), Left("1st!"), Left("2nd!")) 

अब हम (Scalaz 7 का उपयोग कर) लिख सकते हैं:

scala> import scalaz._, Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> xs.sequenceU 
res0: Either[String,List[Int]] = Right(List(1, 2)) 

scala> ys.sequenceU 
res1: Either[String,List[Int]] = Left(1st!) 

के रूप में वांछित।


एक तरफ ध्यान दें के रूप में, इस आपरेशन सिर्फ इतना है कि बाहर कंटेनर traversable हो की आवश्यकता है और अंदर कंटेनर एक अनुप्रयोगी functor हो कि। Scalaz भी एक ValidationNEL वर्ग कि Either की तरह एक बहुत कुछ है और इन आवश्यकताओं का भी फिट बैठता है प्रदान करता है, लेकिन ValidationNEL रों की एक सूची पर sequence उपयोग करने के बजाय पहली बार में रोक के कई त्रुटियों एकत्र करता है:

val zs: List[ValidationNEL[String, Int]] = 
    List(1.successNel, "1st".failNel, "2nd".failNel) 

अब हम पाते हैं:

scala> print(zs.sequenceU) 
Failure(NonEmptyList(1st, 2nd)) 

तुम भी Option रों, Promise रों की एक सूची पर sequence इस्तेमाल कर सकते हैं, आदि

+2

वास्तव में यह अक्का ढांचे में 'भविष्य' परिणाम 'के समान है, है ना? –

+0

@ फिलिपोडेलाका: हाँ, बिल्कुल, यह स्कालाज़ की तुलना में बस कम सामान्य है। –

+0

मैं अभी तक स्कालज़ को पूरी तरह से समझने में सक्षम नहीं हूं, लेकिन मुझे इसे वास्तव में कोशिश करना है, या बेहतर है, इसे मुझे आजमा देना है :) –

2

मैं हमेशा return बयान थोड़ा अजीब है, लेकिन इस निम्नलिखित काम करता है लगता है: आप स्पष्ट वापसी पसंद नहीं है और कुछ हद तक कोड को छोटा करते हुए पैटर्न मिलान को खत्म करना चाहते हैं

def reduce[A, B](xs: Iterable[Either[A, B]]): Either[A, Iterable[B]] = 
    Right(xs.collect { 
    case Left(x) => return Left(x) 
    case Right(x) => x 
    }) 
+1

'मामला बाएं (x) => वापसी बाएं (x) 'को छोटा कर दिया जा सकता है' केस एल @ बाएं (_) => वापसी l' –

+2

@ किमस्टेबल हाँ मैंने सोचा कि पहले, लेकिन' बी' प्रकार पैरामीटर परिणामस्वरूप 'या तो' गलत है (इसके लिए 'Iterable [B] 'की आवश्यकता है लेकिन इसके बजाय' B' है), इसलिए' वाम 'एक अलग' बाएं 'है। –

+0

आह हाँ, यह सच है –

4

, यहाँ एक और है संस्करण:

def reduce[A, B](xs: Iterable[Either[A, B]]): Either[A, Iterable[B]] = 
    xs collectFirst { 
    case Left(x) => Left(x) 
    } getOrElse Right(xs.flatMap(_.right.toOption)) 
+0

इसकी तरह, धन्यवाद। –

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