3

この質問に関して、私unzipList[(A,B)]

List[( (A,B),(C,D) )]ただし、現在、またはのいずれかでマルチ割り当てする必要があることがわかりましたList[(A,B,C,D)]

ペアの unzip とトリプレットの unzip3 があることがわかりましたが、複数の割り当てを行うためにペアTuple2またはシングルをどのように分解するのですか? Tuple4それに応じて以下のコレクション タイプを適応させますが、1 ステップのマルチ割り当てで動作するものはどれでも問題ありません。

// foo can be a List[(A,B,C,D)] OR List[( (A,B),(C,D) )]
val(a,b,c,d) = foo.unzip

これは機能しますが、ハッキングされています

val(a,b,c_d) foo.unzip3 // foo is a List[(A,B,(C,D))]

変数を複数代入することで回避しようとしているまさに表記法c_d._1c_d._2

4

5 に答える 5

6

言うまでもありませんが、複数の手順を気にしない場合は、これを行う簡単な方法があります。

val foo = List((1 -> "w", 'x -> 2.0), (101 -> "Y", 'Z -> 3.0))
val (p, q) = foo.unzip
val (a, b) = p.unzip
val (c, d) = p.unzip

本当にワンライナーが必要な場合は、Scalazのようなものに頼る必要があります。これは、これBifunctorを記述できるタプルのインスタンスを提供します。次に例を示します。

 import scalaz._, Scalaz._

 val ((a, b), (c, d)) = foo.unzip.bimap(_.unzip, _.unzip)

これは基本的に上記のバージョンと同じですが、bimapすべてを1行で実行できます。

于 2012-10-22T12:50:37.150 に答える
3

ここでは、実際には暗黙的な変換は必要ありません。秘訣は、次のようにカスタム抽出オブジェクトを利用することです。

object Unzipped4 {

  def unapply[A, B, C, D](ts: List[(A, B, C, D)]): Some[(List[A], List[B], List[C], List[D])] =
    Some((ts map _._1, ts map _._2, ts map _._3, ts map _._4))

}

次に、次のように使用します。

val Unzipped4(as, bs, cs, ds) = foo

実際には、そのクラスで動的アクセス メソッドを使用してこれを任意のクラスに拡張できますがProduct、その過程で型の安全性がいくらか失われます。

于 2012-10-22T16:27:39.430 に答える
2

他の素晴らしい回答に加えて、私が遊んで、ネストされたアリティジェネリックの解凍について考えました。productIterator私のアプローチは型クラスを使用し、タプルのようにアリティと型の安全性を失います。おそらく、誰かがレスキューのためにshapelessHListを使用してそれを適応させることができます. コレクションで使用する pimp を実装して、呼び出された適切な (同じ) コレクション タイプを返し、を取り除く必要もありますが、ネストされたアリティ ジェネリック unzip のアイデアのみを示すために、ここではこれを省略しました。おそらく、特定の型の Unzippable への具体的な暗黙的な変換がない場合、ある種のLowerPriorityImplicitsを使用して暗黙的に変換することができます。unzipunzipIterableAUnzippable[A,A]

trait Unzippable[T, +Super] {
  def unzip(t: T): Iterable[Super]
}

implicit object IntUnzippable extends Unzippable[Int, Int] { def unzip(i: Int) = Seq(i) }
implicit object BooleanUnzippable extends Unzippable[Boolean, Boolean] { def unzip(b: Boolean) = Seq(b) }
implicit object StringUnzippable extends Unzippable[String, String] { def unzip(s: String) = Seq(s) }

implicit def Tuple2Unzippable[Super, A <: Super, B <: Super, S, S1 <: S, S2 <: S](implicit ev1: Unzippable[A, S1], ev2: Unzippable[B, S2]) = new Unzippable[(A, B), S] {
  def unzip(t: (A, B)): Iterable[S] = ev1.unzip(t._1) ++ ev2.unzip(t._2)
}

def unzip[A, Super](i: Iterable[A])(implicit ev: Unzippable[A, Super]): Iterable[Iterable[Super]] = i.map(ev.unzip).transpose

object MyTuple3 {
  def unapply[X](i: Iterable[X]): Option[(X, X, X)] = if (i.size != 3) return None else Some((i.head, i.drop(1).head, i.last))
}

val list = (1, ("A", true)) :: (2, ("B", false)) :: (3, ("C", true)) :: Nil
val MyTuple3(nums, letters, bools) = unzip(list)
println((nums, letters, bools)) // (List(1, 2, 3),List(A, B, C),List(true, false, true))
于 2012-10-22T18:41:32.570 に答える
2

unzipとしかunzip3ないので、そのための拡張機能を書いてみませんか? このようなものが動作するはずです (2.10 コード):

implicit class Unzip4[A,B,C,D](val xs: List[(A,B,C,D)]) extends AnyVal {
  def unzip4: (List[A], List[B], List[C], List[D]) = xs.foldRight[(List[A], List[B], List[C], List[D])]((Nil,Nil,Nil,Nil)) { (x, res) =>
    val (a,b,c,d) = x
    (a :: res._1, b :: res._2, c :: res._3, d :: res._4)
  }
}
于 2012-10-22T11:06:41.257 に答える
2

unzip4独自のメソッドを追加できます。

import scala.collection._
import generic._

class Unzipper[A, CC[X] <: GenTraversable[X]](s: GenericTraversableTemplate[A, CC]) {
  def unzip4[A1, A2, A3, A4](implicit asQuad: A => (A1, A2, A3, A4)): (CC[A1], CC[A2], CC[A3], CC[A4]) = {
    val b1 = s.genericBuilder[A1]
    val b2 = s.genericBuilder[A2]
    val b3 = s.genericBuilder[A3]
    val b4 = s.genericBuilder[A4]
    for (e <- s) {
      val (a, b, c, d) = asQuad(e)
      b1 += a
      b2 += b
      b3 += c
      b4 += d
    }
    (b1.result, b2.result, b3.result, b4.result)
  }
}

implicit def toUnzipper[A, CC[X] <: GenTraversable[X]](s: GenericTraversableTemplate[A, CC]) = new Unzipper(s)
implicit def t2t2Tot4[A1, A2, A3, A4](tt: ((A1, A2), (A3, A4))) = tt match { case ((a, b), (c, d)) => (a, b, c, d) }
implicit def t1t3Tot4[A1, A2, A3, A4](tt: (A1, (A2, A3, A4))) = tt match { case (a, (b, c, d)) => (a, b, c, d) }
implicit def t3t1Tot4[A1, A2, A3, A4](tt: ((A1, A2, A3), A4)) = tt match { case ((a, b, c), d) => (a, b, c, d) }

使用法:

scala> List((1, 2, 3, 4)).unzip4
res0: (List[Int], List[Int], List[Int], List[Int]) = (List(1),List(2),List(3),List(4))

scala> List((1, 2) -> (3, 4)).unzip4
res1: (List[Int], List[Int], List[Int], List[Int]) = (List(1),List(2),List(3),List(4))

scala> List(1 -> (2, 3, 4)).unzip4
res2: (List[Int], List[Int], List[Int], List[Int]) = (List(1),List(2),List(3),List(4))

scala> List((1, 2, 3) -> 4).unzip4
res3: (List[Int], List[Int], List[Int], List[Int]) = (List(1),List(2),List(3),List(4))
于 2012-10-22T11:17:51.423 に答える