【问题标题】:How to convert a Seq of Tuple2s of Tuple2s to a Tuple2 of Maps如何将 Tuple2 的 Tuple2 的 Seq 转换为 Maps 的 Tuple2
【发布时间】:2013-11-06 05:52:42
【问题描述】:

我有一个想要转换成一对地图的数据序列;每个映射代表原始序列的单独转换。我可以生成元组,这些元组将在原始输入序列的单次传递中构成每个映射,如下所示:

val entries: Seq[((A, B), (A, C))] = input map { x =>
  val key = genKey(x)
  val tuple1 = key -> f(x)
  val tuple2 = key -> g(x)
}

我可以通过两次遍历生成的 seq 来单独创建每个映射,如下所示:

val map1 = (entries map { case(e1, _) => e1 }).toMap
val map2 = (entries map { case(_, e2) => e2 }).toMap

我认为可能有一种方法可以在地图上一次完成整个转换,这样我就可以做这样的事情:

val (map1, map2) = (entries accumulate { case(e1, e2) => // add e1 to map1, add e2 to map2 })

一个 foldLeft 可能会这样做,但也许有更优雅的东西?

【问题讨论】:

    标签: scala tuples


    【解决方案1】:

    使用标准库:

    val (map1, map2) = entries.unzip match {
      case (pairs1, pairs2) => (pairs1.toMap, pairs2.toMap)
    }
    

    Scalaz 是一条线:

    val (map1, map2) = entries.unzip.bimap(_.toMap, _.toMap)
    

    不过,这两种解决方案都会创建两个额外的中间序列。这可能不是你需要担心的事情,但如果你真的想避免它,折叠实际上并不是那么不雅:

    val (map1, map2) = entries.foldLeft(Map.empty[A, B], Map.empty[A, C]) {
      case ((map1, map2), (pair1, pair2)) => (map1 + pair1, map2 + pair2)
    }
    

    不需要 Scalaz。

    【讨论】:

      【解决方案2】:

      如果你想使用上面的entries 方法,那么显而易见的方法是:

      val (s1, s2) = entries.unzip
      val map1 = s1.toMap
      val map2 = s2.toMap
      

      但是,您仍然 (1) 遍历您的 inputs 以创建元组序列,然后 (2) 再次遍历 unzip,然后 (3) 遍历 s1.toMap,然后 (4) 再次在s2.toMap.

      如果您关心的是最少的遍历,正如您的问题所暗示的那样,您需要手动构建结果。优雅,不,但直截了当,您可以取消 entries 方法。

      val (map1, map2) = {
        val b1, b2 = Map.newBuilder[Int, String]
        input foreach { i =>
          val k = genKey(i)
          b1 += k -> f(i)
          b2 += k -> g(i)
        }
        (b1.result, b2.result)
      }
      

      【讨论】:

        【解决方案3】:

        这将是我的方法(恕我直言,初学者更容易掌握):

        object TupleTest {
        
          def transform[A, B, C](entries: Seq[((A, B), (A, C))]): (Map[A, B], Map[A, C]) =
            {
        
              def acc[A, B, C](entries: Seq[((A, B), (A, C))], map1: Map[A, B], map2: Map[A, C]): (Map[A, B], Map[A, C]) =
                {
                  entries match {
                    case Nil => (map1, map2)
                    case hd :: tl => acc(tl, map1.+(hd._1), map2.+(hd._2))
                  }
        
                }
              acc(entries, Map.empty[A, B], Map.empty[A, C])
        
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 2012-10-11
          • 2012-10-05
          • 2017-07-16
          • 1970-01-01
          • 2014-12-19
          • 1970-01-01
          • 2021-04-12
          • 2013-01-11
          • 1970-01-01
          相关资源
          最近更新 更多