list - स्काला विभाजन/संग्रह उपयोग




scala collect (4)

मुझे यहाँ इस मूल समस्या का संतोषजनक समाधान नहीं मिला। मुझे कलेक्शन पर लेक्चर की जरूरत नहीं है और अगर यह किसी का होमवर्क है तो परवाह न करें। इसके अलावा, मैं ऐसा कुछ नहीं चाहता जो केवल 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
  }
}

उदाहरण usages:

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])

क्या 2 नई सूची बनाने के लिए एक कॉल का उपयोग करना संभव है? यदि नहीं, तो मैं partition का उपयोग करके यह कैसे कर सकता हूं?


मैं इसका उपयोग करता हूं। इसके बारे में एक अच्छी बात यह है कि यह एक विभाजन में विभाजन और मानचित्रण को जोड़ती है। एक दोष यह है कि यह अस्थायी वस्तुओं का एक गुच्छा आवंटित करता है ( 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)

Scala 2.13 शुरू करते हुए, अधिकांश संग्रह अब एक partitionMap विधि के साथ प्रदान किए जाते हैं, जो एक फ़ंक्शन के आधार पर तत्वों को विभाजित करता है जो कि Right या Left लौटता है।

यह हमें टाइप के आधार पर मिलान करने की अनुमति देता है (जो एक collect रूप में विभाजन सूचियों में विशिष्ट प्रकार के सक्षम बनाता है) या कोई अन्य पैटर्न:

 val (strings, ints) =
   List("a", 1, 2, "b", 19).partitionMap {
     case s: String => Left(s)
     case x: Int    => Right(x)
   }
 // strings: List[String] = List("a", "b")
 // ints: List[Int] = List(1, 2, 19)

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

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

जो वास्तव में एक विशेष मामला है

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

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

तो आप क्या करते हैं यदि आप चाहते हैं कि कई शर्तें हों, जिसके परिणामस्वरूप आपकी सूची अलग-अलग टुकड़ों में विभाजित हो जाए? एक तरीका एक संकेतक फ़ंक्शन A => Int , जहां आपके A को एक गिने हुए वर्ग में मैप किया गया है, और फिर groupBy उपयोग 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 इस मामले में) द्वारा अपनी उप-सूचियाँ देख सकते हैं। दुर्भाग्य से, यदि आप कुछ जानकारी को अनदेखा करना चाहते हैं, तो आपको अभी भी उन्हें एक कक्षा में रखना होगा (जैसे कि आप शायद इस मामले में किसी की कई प्रतियों के बारे में परवाह नहीं करते हैं)।





collect