关于this question我可以通过unzip
List[(A,B)]
多次分配
但是,现在我发现需要在List[( (A,B),(C,D) )]
或List[(A,B,C,D)]
我看到有成对的解压缩和三胞胎的unzip3,但是如何解构一对Tuple2
或单个Tuple4
以便进行多指派?我将相应调整下面的集合类型,但无论哪一个适用于一步多任务都可以。
// 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._1
和c_d._2
,这是我试图通过多分配变量来避免的符号
答案 0 :(得分: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 :(得分: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
,但在此过程中您将失去一些类型安全性。
答案 2 :(得分: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)
}
}
答案 3 :(得分: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))
答案 4 :(得分:2)
除了我玩的其他很棒的答案,还考虑过嵌套和arity-generic解压缩。我的方法使用类型类并丢失arity并在元组上键入productIterator
之类的安全性。也许有人可以使用shapeless中的HList
进行调整以进行救援。还必须实现pimp我的库在集合上使用unzip
来返回被调用的正确(相同)集合类型unzip
并删除Iterable
,但我省略了这个这里只展示嵌套arity-generic解压缩的想法。如果对于给定类型没有具体的隐式转换为Unzippable,也许可以使用某种 LowerPriorityImplicits 来隐式地将任何A
转换为Unzippable[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))