2011-01-24 12 views

उत्तर

75

collect (सभी उपवर्गों में TraversableLike पर परिभाषित और उपलब्ध है) संग्रह के साथ काम करता है और PartialFunction। यह भी सिर्फ इतना है कि मामले खंड ब्रेसिज़ के अंदर परिभाषित के एक समूह के एक आंशिक समारोह (Scala Language Specificationकी धारा 8.5 देखें [चेतावनी - पीडीएफ]) कर रहे हैं

अपवाद संचालन में के रूप में:

try { 
    ... do something risky ... 
} catch { 
    //The contents of this catch block are a partial function 
    case e: IOException => ... 
    case e: OtherException => ... 
} 

यह एक फ़ंक्शन को परिभाषित करने का एक आसान तरीका जो केवल किसी दिए गए प्रकार के कुछ मान स्वीकार करेगा।

मिश्रित मानों की सूची पर उपयोग पर विचार करें:

val mixedList = List("a", 1, 2, "b", 19, 42.0) //this is a List[Any] 
val results = mixedList collect { 
    case s: String => "String:" + s 
    case i: Int => "Int:" + i.toString 
} 

तर्क collect करने के लिए विधि एक PartialFunction[Any,String] है। PartialFunction क्योंकि यह Any (List का प्रकार होने) और String के सभी संभावित इनपुट के लिए परिभाषित नहीं है क्योंकि यह सभी खंड वापस आते हैं।

आप collect के बजाय map उपयोग करने का प्रयास करते हैं, तो mixedList के अंत में डबल मूल्य एक MatchError का कारण होगा। collect का उपयोग करके बस इसे छोड़ दें, साथ ही साथ कोई अन्य मान जिसके लिए पार्टिकल फ़ंक्शन परिभाषित नहीं किया गया है। इस तरह एक युद्ध अपराध होने के लिए कई द्वारा माना जाता है हालांकि यह सिर्फ एक उदाहरण है

var strings = List.empty[String] 
var ints = List.empty[Int] 
mixedList collect { 
    case s: String => strings :+= s 
    case i: Int => ints :+= i 
} 

, परिवर्तनशील वैरिएबल का उपयोग कर - इसलिए कृपया:

एक संभावित उपयोग सूची के तत्वों को अलग तर्क लागू करने के लिए किया जाएगा ऐसा मत करो!

एक ज्यादा बेहतर समाधान दो बार इकट्ठा उपयोग करने के लिए है:

val strings = mixedList collect { case s: String => s } 
val ints = mixedList collect { case i: Int => i } 

या यदि आप कुछ के लिए पता है कि इस सूची में केवल मूल्यों के दो प्रकार के होते हैं, आप partition, जो मूल्यों में एक संग्रह विभाजन का उपयोग कर सकते चाहे या नहीं वे कुछ विधेय से मेल खाते हैं पर निर्भर करता है:

//if the list only contains Strings and Ints: 
val (strings, ints) = mixedList partition { case s: String => true; case _ => false } 

यहाँ पकड़ है कि दोनों strings और ints प्रकारके हैं, यद्यपि आप आसानी से उन्हें कुछ और प्रकारों पर वापस कर सकते हैं (शायद collect का उपयोग करके ...)

यदि आपके पास पहले से ही एक प्रकार का सुरक्षित संग्रह है और तत्वों की किसी अन्य संपत्ति पर विभाजित करना चाहते हैं, तो चीजें हैं आपके लिए थोड़ा आसान:

val intList = List(2,7,9,1,6,5,8,2,4,6,2,9,8) 
val (big,small) = intList partition (_ > 5) 
//big and small are both now List[Int]s 

आशा है कि यह बताता है कि दोनों विधियां यहां आपकी मदद कैसे कर सकती हैं!

+3

का भी उपयोग कर रहा हूं बहुत अच्छी व्याख्या, लेकिन मुझे लगता है कि ओपी चाहता है कि' संग्रह 'और' विभाजन 'का संयोजन है जो एकत्रित मूल्यों और सूची की सूची का एक टुपल देता है बाकी सभी का। 'def संग्रह और विभाजन [ए, बी] (पीएफ: आंशिक समारोह [ए, बी]): (सूची [बी], सूची [ए])'। यह मूल रूप से देशी लाइब्रेरी फ़ंक्शन के साथ सबसे सुंदर रूप से हासिल किया जाएगा, यानी ट्रैवर्सबल में 'संग्रह' के स्रोत में हमारे पास 'x <- this) है (pf.isDefinedAt (x)) b + = pf (x) ' , कोई भी उस के अंत में 'else a + = x' को आसानी से ले सकता है, जहां' बाकी 'बाकी की सूची के लिए एक निर्माता होगा। –

+3

मुझे पता है कि ओपी को क्या चाहिए, और मुझे यह भी पता है कि यह एक होमवर्क प्रश्न है (हाल ही में स्टैक ओवरफ्लो पर इसका उल्लेख किया गया है), इसलिए मैं वास्तव में इसे हल किए बिना बहुत सारे सिद्धांत प्रदान करूंगा। संग्रह और विभाजन के लिए, मैंने पहले से ही लिखा है, हालांकि मैंने विधि 'कोलेट' नाम दिया है।यदि कोई उस स्तर पर स्कैला पढ़ रहा है जहां छात्रों को CanBuildFrom के साथ काम करने की उम्मीद है तो मैं बहुत आश्चर्यचकित हूं, यह वर्तमान में उत्पादन में स्कैला का उपयोग करने वाले अधिकांश लोगों से परे है। –

+0

वह बहुत उपयोगी था। लेकिन मैं अभी भी सोच रहा हूं ... क्या आप "युद्ध अपराध" के बिना सकारात्मक और नकारात्मक मूल्यों को अलग करना संभव है, जैसा आपने लिखा था? मैं सिर्फ उत्सुक हूं क्योंकि मैंने विभाजन का उपयोग करने के साथ पहले ही होमवर्क किया है। ओह ... और वैसे, मदद के लिए धन्यवाद! –

6

कैसे परिवर्तनशील सूचियों का उपयोग किए बिना collect साथ यह करने के लिए है, लेकिन partition के रूप में अच्छी तरह से (सिर्फ एक छोटे से अधिक शब्द) मिलान पैटर्न का उपयोग कर सकते हैं सुनिश्चित नहीं हैं कि

List("a", 1, 2, "b", 19).partition { 
    case s:String => true 
    case _ => false 
} 
+0

@coubeatczech - क्योंकि विभाजन एक रिटर्न '(सूची [एक], सूची [एक])'। यह सब कुछ कर सकता है क्योंकि इनपुट 'सूची [ए]' और एक सूचक कार्य 'ए => बूलियन' है। इसका यह जानने का कोई तरीका नहीं है कि सूचक कार्य प्रकार-विशिष्ट हो सकता है। –

+1

@Rex मैंने अपने स्वयं के 'कोलेट' विधि को उन संग्रहों पर भंग करने के लिए परिभाषित किया जो इस समस्या को हल करते हैं। 'सूची [ए]' पर उपयोग-केस हस्ताक्षर 'कोलेट [बी] (एफएन: आंशिक समारोह [ए, बी]): (सूची (बी), सूची (ए)), जाहिर है * वास्तविक * हस्ताक्षर है इससे थोड़ा बालों वाला है क्योंकि मैं 'CanBuildFrom' –

5

सामान्य रूप से इस्तेमाल किया collect पर, कहते हैं, Seq के हस्ताक्षर,

collect[B](pf: PartialFunction[A,B]): Seq[B] 

जो वास्तव में

collect[B, That](pf: PartialFunction[A,B])(
    implicit bf: CanBuildFrom[Seq[A], B, That] 
): That 

तो की एक विशेष विषय है यदि आप डिफ़ॉल्ट मोड में इसका इस्तेमाल होता है, जवाब नहीं है, निश्चित रूप से नहीं: आपको इससे बिल्कुल एक अनुक्रम मिलता है। यदि आप CanBuildFromBuilder के माध्यम से अनुसरण करते हैं, तो आप देखते हैं कि That वास्तव में दो अनुक्रमों को बनाना संभव होगा, लेकिन यह कहने का कोई तरीका नहीं होगा कि किसी अनुक्रम को किस क्रम में जाना चाहिए, क्योंकि आंशिक कार्य केवल "हाँ, मैं कह सकता हूं" संबंधित "या" नहीं, मैं संबंधित नहीं हूं "।

तो आप क्या करते हैं यदि आप कई स्थितियां चाहते हैं जिसके परिणामस्वरूप आपकी सूची अलग-अलग टुकड़ों के समूह में विभाजित हो? एक तरीका एक सूचक फ़ंक्शन A => Int बनाना है, जहां आपका A एक क्रमांकित वर्ग में मैप किया गया है, और उसके बाद groupBy का उपयोग करें। उदाहरण के लिए:

def optionClass(a: Any) = a match { 
    case None => 0 
    case Some(x) => 1 
    case _ => 2 
} 
scala> List(None,3,Some(2),5,None).groupBy(optionClass) 
res11: scala.collection.immutable.Map[Int,List[Any]] = 
    Map((2,List(3, 5)), (1,List(Some(2))), (0,List(None, None))) 

अब आप अपनी उप-सूचियां इस मामले में कक्षा (0, 1, और 2) देख सकते हैं। दुर्भाग्यवश, यदि आप कुछ इनपुटों को अनदेखा करना चाहते हैं, तो आपको अभी भी उन्हें एक कक्षा में रखना होगा (उदाहरण के लिए आपको शायद इस मामले में None की कई प्रतियों की परवाह नहीं है)।

3

मैं इसका उपयोग करता हूं। इसके बारे में एक अच्छी बात यह है कि यह एक पुनरावृत्ति में विभाजन और मैपिंग को जोड़ती है। एक दोष यह है कि यह अस्थायी वस्तुओं का एक समूह (Either.Left और Either.Right उदाहरणों)

/** 
* Splits the input list into a list of B's and a list of C's, depending on which type of value the mapper function returns. 
*/ 
def mapSplit[A,B,C](in: List[A])(mapper: (A) => Either[B,C]): (List[B], List[C]) = { 
    @tailrec 
    def mapSplit0(in: List[A], bs: List[B], cs: List[C]): (List[B], List[C]) = { 
    in match { 
     case a :: as => 
     mapper(a) match { 
      case Left(b) => mapSplit0(as, b :: bs, cs ) 
      case Right(c) => mapSplit0(as, bs,  c :: cs) 
     } 
     case Nil => 
     (bs.reverse, cs.reverse) 
    } 
    } 

    mapSplit0(in, Nil, Nil) 
} 

val got = mapSplit(List(1,2,3,4,5)) { 
    case x if x % 2 == 0 => Left(x) 
    case y    => Right(y.toString * y) 
} 

assertEquals((List(2,4),List("1","333","55555")), got) 
1

आवंटित करता है मैं यहाँ इस बुनियादी समस्या के लिए एक संतोषजनक समाधान नहीं मिल सका है। मुझे collect पर व्याख्यान की आवश्यकता नहीं है और यह परवाह नहीं है कि यह किसी का होमवर्क है या नहीं। साथ ही, मुझे ऐसा कुछ नहीं चाहिए जो केवल List के लिए काम करता हो।

तो यहां मेरा स्टैब है। कुशल और किसी भी TraversableOnce के साथ संगत, यहां तक ​​कि तार:

implicit class TraversableOnceHelper[A,Repr](private val repr: Repr)(implicit isTrav: Repr => TraversableOnce[A]) { 

    def collectPartition[B,Left](pf: PartialFunction[A, B]) 
    (implicit bfLeft: CanBuildFrom[Repr, B, Left], bfRight: CanBuildFrom[Repr, A, Repr]): (Left, Repr) = { 
    val left = bfLeft(repr) 
    val right = bfRight(repr) 
    val it = repr.toIterator 
    while (it.hasNext) { 
     val next = it.next 
     if (!pf.runWith(left += _)(next)) right += next 
    } 
    left.result -> right.result 
    } 

    def mapSplit[B,C,Left,Right](f: A => Either[B,C]) 
    (implicit bfLeft: CanBuildFrom[Repr, B, Left], bfRight: CanBuildFrom[Repr, C, Right]): (Left, Right) = { 
    val left = bfLeft(repr) 
    val right = bfRight(repr) 
    val it = repr.toIterator 
    while (it.hasNext) { 
     f(it.next) match { 
     case Left(next) => left += next 
     case Right(next) => right += next 
     } 
    } 
    left.result -> right.result 
    } 
} 

उदाहरण उपयोगों:

val (syms, ints) = 
    Seq(Left('ok), Right(42), Right(666), Left('ko), Right(-1)) mapSplit identity 

val ctx = Map('a -> 1, 'b -> 2) map {case(n,v) => n->(n,v)} 
val (bound, unbound) = Vector('a, 'a, 'c, 'b) collectPartition ctx 
println(bound: Vector[(Symbol, Int)], unbound: Vector[Symbol]) 
संबंधित मुद्दे