2013-02-27 24 views
7

मेरे पास एक मॉडल है, जिसमें कुछ विकल्प फ़ील्ड हैं, जिनमें एक और विकल्प फ़ील्ड हैं। उदाहरण के लिए:अन्य विकल्प ऑब्जेक्ट के अंदर स्कैला विकल्प ऑब्जेक्ट

case class First(second: Option[Second], name: Option[String]) 
case class Second(third: Option[Third], title: Option[String]) 
case class Third(numberOfSmth: Option[Int]) 

मैं बाहरी JSON के से इस डेटा प्राप्त कर रहा हूँ और कभी कभी यह डाटा शून्य के शामिल हो सकता है, कि इस तरह के मॉडल के डिजाइन के कारण था।

तो सवाल यह है कि: गहरा क्षेत्र पाने का सबसे अच्छा तरीका क्या है?

First.get.second.get.third.get.numberOfSmth.get 

उपरोक्त विधि वास्तव में बदसूरत लगती है और यदि कोई ऑब्जेक्ट कोई नहीं होगा तो यह अपवाद हो सकता है। मैं Scalaz lib में देख रहा था, लेकिन ऐसा करने के लिए एक बेहतर तरीका नहीं पता था।

कोई विचार? अग्रिम धन्यवाद।

+2

बस एक नोट लेकिन flatMap woun ':

यहाँ आरईपीएल (4 शैलियों, बराबर हैं पहले दो flatMap घोंसले का उपयोग कर, अन्य दो flatMap के फ्लैट चेन उपयोग करने के साथ) में कुछ उदाहरण है कई बार नीचे दिए गए अनुसार काम नहीं करते हैं। यह 'first.second.flatMap होना चाहिए (_। Third.flatMap (_। NumberOfSmth))। प्राप्त करें 'और अभी भी फेंक सकता है और अपवाद – korefn

+0

वास्तव में, धन्यवाद। आपके उत्तरों के लिए सभी को धन्यवाद, मैंने पाया है कि मैं क्या देख रहा था। – psisoyev

उत्तर

14

समाधान Option.map और Option.flatMap उपयोग करने के लिए है कि numberOfSmth एक Int देता है)। यदि कॉल श्रृंखला में से कोई भी विकल्प None है, तो परिणाम None होगा, अन्यथा यह Some(count) होगा जहां countnumberOfSmth द्वारा दिया गया मान है।

बेशक यह बदसूरत हो सकता है। इस कारण से स्कैला को को वाक्य रचनात्मक चीनी के रूप में समर्थन देता है।

for { 
    first <- First 
    second <- first .second 
    third <- second.third 
} third.numberOfSmth 

कौन सा यकीनन अच्छे है (विशेष रूप से अगर आप अभी तक, map/flatMap हर जगह देखने के अभ्यस्त नहीं कर रहे हैं के रूप में निश्चित रूप से कुछ समय के स्केला उपयोग करने के बाद मामला हो जाएगा), और सटीक उत्पन्न करता है: जैसा कि ऊपर लिखा जा सकता है हुड के नीचे एक ही कोड। What is Scala's yield?

अद्यतन: उनका कहना है कि flatMap साहचर्य है के लिए बेन जेम्स धन्यवाद

अधिक पृष्ठभूमि के लिए, आप इस दूसरे प्रश्न की जांच कर सकते हैं। दूसरे शब्दों में x flatMap(y flatMap z)))x flatMap y flatMap z जैसा ही है। जबकि उत्तरार्द्ध आमतौर पर छोटा नहीं होता है, लेकिन इसका किसी भी घोंसले से बचने का लाभ होता है, जो कि पालन करना आसान है।

scala> val l = Some(1,Some(2,Some(3,"aze"))) 
l: Some[(Int, Some[(Int, Some[(Int, String)])])] = Some((1,Some((2,Some((3,aze)))))) 
scala> l.flatMap(_._2.flatMap(_._2.map(_._2))) 
res22: Option[String] = Some(aze) 
scala> l flatMap(_._2 flatMap(_._2 map(_._2))) 
res23: Option[String] = Some(aze) 
scala> l flatMap(_._2) flatMap(_._2) map(_._2) 
res24: Option[String] = Some(aze) 
scala> l.flatMap(_._2).flatMap(_._2).map(_._2) 
res25: Option[String] = Some(aze) 
+3

आपको बदसूरत घोंसले का उपयोग करने की आवश्यकता नहीं है: 'फ्लैटमैप 'की साझेदारी की वजह से,' एक फ्लैटमैप (बी फ्लैटमैप सी)' 'फ्लैटमैप बी फ्लैटमैप सी' –

+0

के बराबर है, धन्यवाद, आप बहुत सही हैं। मैं आमतौर पर उन्हें घोंसला करता हूं क्योंकि यह मैप किए गए/फ्लैट मैप किए गए वास्तविक संरचना की नकल करता है (जो ** इस मामले में ** नेस्टेड है)। लेकिन यह सच है कि यह 'flatMap' की एक फ्लैट श्रृंखला के रूप में अधिक पठनीय है। –

+1

ध्यान दें कि फ्लैट मैप्स को घोंसला नहीं है, नेस्टेड लैम्ब्डा अभिव्यक्तियों में लैम्ब्डा पैरामीटर का उपयोग करने में सक्षम नहीं होने का नुकसान होता है, हालांकि यह इस मामले में काम करता है, लेकिन मैं इसे सामान्य की अनुशंसा नहीं करता। यह भी धीमा है और अधिक कार्य वस्तुओं बनाता है। –

4

यह flatMap के चेनिंग कॉल करके किया जा सकता:

def getN(first: Option[First]): Option[Int] = 
    first flatMap (_.second) flatMap (_.third) flatMap (_.numberOfSmth) 

तुम भी एक के लिए-समझ के साथ ऐसा कर सकते हैं, लेकिन इसे और अधिक वर्बोज़ के रूप में यह तुम बलों प्रत्येक मध्यवर्ती मूल्य नाम के लिए है:

def getN(first: Option[First]): Option[Int] = 
    for { 
    f <- first 
    s <- f.second 
    t <- s.third 
    n <- t.numberOfSmth 
    } yield n 
10

scalaz के लिए कोई जरूरत नहीं है:

for { 
    first <- yourFirst 
    second <- f.second 
    third <- second.third 
    number <- third.numberOfSmth 
} yield number 

वैकल्पिक रूप से आप ग एक प्रयोग नेस्ट flatMaps

0

मुझे लगता है कि आपकी समस्या के लिए लेकिन सिर्फ एक सामान्य संदर्भ के रूप में एक overkill है:

यह नेस्टेड पहुँच समस्या एक अवधारणा बुलाया लेंस से संबोधित किया जाता है। वे सरल संरचना द्वारा नेस्टेड डेटा प्रकारों तक पहुंचने के लिए एक अच्छा तंत्र प्रदान करते हैं। परिचय के रूप में आप उदाहरण this SO answer या this tutorial के लिए जांचना चाहेंगे। सवाल यह है कि क्या आपके मामले में लेंस का उपयोग करना समझ में आता है कि क्या आपको नेस्टेड विकल्प संरचना में बहुत सारे अपडेट करना पड़ता है (नोट: अद्यतन करने योग्य अर्थ में नहीं, बल्कि एक नया संशोधित लेकिन अपरिवर्तनीय उदाहरण लौटा रहा है)। लेंस के बिना यह लंबे समय से घोंसला केस वर्ग copy कोड की ओर जाता है। अगर आपको बिल्कुल अपडेट नहीं करना है, तो मैं om-nom-nom's suggestion पर रहूंगा। (बशर्ते

First flatMap(_.second) flatMap(_.third) map(_.numberOfSmth) 

यह एक Option[Int] रिटर्न: (इस जवाब के अंत में अद्यतन देख)

First.flatMap(_.second.flatMap(_.third.map(_.numberOfSmth))) 

या समकक्ष:

+2

@ डाउनवॉटर: क्या आप डाउनवोट की व्याख्या करना चाहते हैं? ओपी को देखते हुए इस नेस्टेड संरचना को बहुत अद्यतन करना है, मुझे लगता है कि ओपी को वैकल्पिक समाधान के रूप में लेंस की अवधारणा को इंगित करने की अनुमति दी जानी चाहिए? – bluenote10

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