2012-08-05 35 views
5

मैं दो Option[Iterable[_]] को एक नए Option[Iterable[_]] में गठबंधन करने की कोशिश कर रहा हूं। मैं कुछ वापस करना चाहूंगा यदि तत्वों में से एक (या दोनों) कुछ है और कोई अन्यथा नहीं है। ऐसा लगता है कि ऐसा करने का एक बेवकूफ तरीका होना चाहिए, लेकिन मुझे लगता है कि एक नहीं मिल रहा है। ऐसा लगता है कि मैं जो चाहता हूं वह करना है, लेकिन यह काफी हद तक समाधान नहीं है जिसे मैं उम्मीद कर रहा था।स्केल विकल्प का संयोजन [Iterable [_]]

def merge(
    i1: Option[Iterable[_]], i2: Option[Iterable[_]] 
): Option[Iterable[_]] = (i1, i2) match { 
    case (Some(as), Some(bs)) => Some(as ++ bs) 
    case (a @ Some(as), None) => a 
    case (None, b @ Some(bs)) => b 
    case _ => None 
} 

किसी भी सुझाव की सराहना की जाती है। धन्यवाद!

+0

तरह के लगभग समान प्रश्न: http://stackoverflow.com/questions/10617979/binary-operator-with-option-arguments/10618340#10618340, उपयोगी हो सकता है –

उत्तर

11

यदि आप सार बीजगणित का एक सा के साथ प्रस्तुत करने को तैयार हैं, यहाँ एक अच्छा सामान्यीकरण है कॉन्सटेनेशन के तहत, जहां एक मोनॉयड केवल कुछ चीजों का सेट होता है (इस मामले में पुन: संग्रहित संग्रह) और कुछ सरल गुणों और एक पहचान तत्व (खाली संग्रह) के साथ एक अतिरिक्त-जैसे ऑपरेशन (कॉन्सटेनेशन)।

Some(xs) + Some(ys) == Some(xs + ys) 
Some(xs) + None  == Some(xs) 
None  + Some(ys) == Some(ys) 
None  + None  == None 

(ध्यान दें कि हम इस तथ्य है कि A एक monoid पता करने के लिए क्या है की जरूरत है:

इसी प्रकार, यदि A एक monoid है, तो Option[A] भी अपने merge के एक से थोड़ा अधिक सामान्य संस्करण के तहत एक monoid है । पहली पंक्ति में करने के लिए)

Scalaz library अपने Monoid प्रकार वर्ग है, जो देता है में इन सभी सामान्यीकरण कब्जा आप लिखते हैं अपने merge इस तरह:

012,
import scalaz._, Scalaz._ 

def merge(i1: Option[Iterable[_]], i2: Option[Iterable[_]]) = i1 |+| i2 

कौन सा अपेक्षा के अनुरूप काम करता है:

scala> merge(Some(1 to 5), None) 
res0: Option[Iterable[_]] = Some(Range(1, 2, 3, 4, 5)) 

scala> merge(Some(1 to 5), Some(4 :: 3 :: 2 :: 1 :: Nil)) 
res1: Option[Iterable[_]] = Some(Vector(1, 2, 3, 4, 5, 4, 3, 2, 1)) 

scala> merge(None, None) 
res2: Option[Iterable[_]] = None 

(नोट अन्य कार्यों कि Iterable और Option के लिए मान्य Monoid उदाहरणों देना होगा देखते हैं कि, लेकिन तुम्हारा सबसे अधिक इस्तेमाल किया है, और जो कि Scalaz द्वारा प्रदान करता है डिफ़ॉल्ट)

+0

ग्रेट उत्तर। सोचें कि पहले कोड खंड की तीसरी पंक्ति में एक मामूली टाइपो है, == कुछ (वाईएस) होना चाहिए? –

+0

@ ब्रायनस्मिथ: हां, ज़ाहिर है-पकड़ने के लिए धन्यवाद! –

3

यह काम करता है: यदि और केवल यदि दोनों हैं Some

def merge(i1: Option[Iterable[_]], i2: Option[Iterable[_]]): Option[Iterable[_]] = 
    (for (a <- i1; b <- i2) yield a ++ b).orElse(i1).orElse(i2) 

for/yield भाग विकल्पों में से सामग्री जोड़ देगा।

तुम भी डॉट्स और कोष्ठक में से कुछ को छोड़ सकते हैं अगर आप चाहते हैं: Iterable[_] एक monoid है:

(for (a <- i1; b <- i2) yield a ++ b) orElse i1 orElse i2 
+0

आह, हाँ। यह बहुत अच्छा है - धन्यवाद। – robo

1

आप मनमाने ढंग से arity के लिए इसका उपयोग कर सकते हैं:।

def merge(xs: Option[Iterable[_]]*) = 
    if (xs.forall(_.isEmpty)) None else Some(xs.flatten.flatten) 
संबंधित मुद्दे