【问题标题】:Scala: map and unzip list in one passScala:一次映射和解压缩列表
【发布时间】:2018-10-13 05:12:45
【问题描述】:

我有一个元组列表如下:

[(8, 3, 9), (10, 3, 0), (-37, 4, 1)]

我想映射这个列表并同时解压缩它一次性。这是一个包含两次传递的示例(或者至少我强烈假设它需要两次传递,如果不是,那么我们就在这里完成了:D)

val l = List((8, 3, 9), (10, 3, 0), (-37, 4, 1))
val (list1, list2) = l.map({ el => (el._1, el._2) }).unzip

当然,我可以通过循环遍历列表并附加到集合来以命令式的方式执行此操作,但是有没有办法以简洁的功能方式执行此操作?我猜我基本上需要一个懒惰的map,然后是一个急切的unzip

【问题讨论】:

    标签: scala list dictionary collections tuples


    【解决方案1】:

    这非常具体到您所说的问题;它不能解决更普遍的问题。试试:

    val (list1, list2, _) = l.unzip3
    

    编辑

    公平地说,在找到实现 scala.collection.generic.GenericTraversableTemplate.unzip3 之后,这是一个非常无功能的循环,它构建 3 个列表并返回它们,与原始问题中的描述非常相似。至少是一次传球,而不是埋没二次传球。

    【讨论】:

      【解决方案2】:

      总是有fold

      val (list1, list2) = l.foldRight((List.empty[Int],List.empty[Int])){
        case ((a,b,_),(l1,l2)) => (a::l1,b::l2)
      }
      

      【讨论】:

        【解决方案3】:

        unzip 与函数一起使用

        在 Scala 中,unzip 操作将函数作为隐式参数来生成该对,因此您可以一次性完成 mapunzip。这是 Scala 2.13.4 docsList 的样子:

        def unzip[A1, A2](implicit asPair: (A) => (A1, A2)): (List[A1], List[A2])
        

        通过传递您自己的asPair 函数,您可以完成您正在寻找的结果:

        scala> val l = List((8, 3, 9), (10, 3, 0), (-37, 4, 1))
        val l: List[(Int, Int, Int)] = List((8,3,9), (10,3,0), (-37,4,1))
        
        scala> val (list1, list2) = l.unzip(el => (el._1, el._2))
        val list1: List[Int] = List(8, 10, -37)
        val list2: List[Int] = List(3, 3, 4)
        

        算法复杂度

        unzip 函数的源代码位于文件 Iterable.scala 中的 trait scala.collection.IterableOps 中:

        def unzip[A1, A2](implicit asPair: A => (A1, A2)): (CC[A1], CC[A2]) = {
          val first: View[A1] = new View.Map[A, A1](this, asPair(_)._1)
          val second: View[A2] = new View.Map[A, A2](this, asPair(_)._2)
          (iterableFactory.from(first), iterableFactory.from(second))
        }
        

        如果我没看错的话,这个列表实际上被遍历了两次:每个列表生成一次。

        但是,在您的原始解决方案中,列表被遍历了 3 次:一次用于 map 操作,两次用于 unzip 操作,所以我的解决方案仍然是一个改进。

        @jwvh 建议的使用foldRight 的解决方案似乎只遍历列表一次,但foldRight 具有最初反转列表的开销(以便从列表的头部获取)。所以我想我的解决方案具有完全相同的算法复杂性。 (如果我错了,请纠正我。)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-11
          • 2016-10-18
          • 2022-01-26
          • 1970-01-01
          相关资源
          最近更新 更多