【问题标题】:Scala: How to convert tuple elements to listsScala:如何将元组元素转换为列表
【发布时间】:2012-09-12 16:13:20
【问题描述】:

假设我有以下元组列表:

val tuples = listOfStrings.map(string => {
            val split = string.split(":")
            (split(0), split(1), split(2))
        })

我想在一个列表中获取 split(0),在另一个列表中获取 split(1),依此类推。 实现这一点的一个简单方法是编写:

list1 = tuples.map(x => x._1).toList
list2 = tuples.map(x => x._2).toList
list3 = tuples.map(x => x._3).toList

有没有更优雅(功能性)的方式来实现上述目标,而无需编写 3 个单独的语句?

【问题讨论】:

    标签: scala tuples higher-order-functions


    【解决方案1】:

    这会给你一个列表的结果:

    tuples.map{t => List(t._1, t._2, t._3)}.transpose
    

    如果您想将它们存储在局部变量中,只需执行以下操作:

    val List(l1,l2,l3) = tuples.map{t => List(t._1, t._2, t._3)}.transpose
    

    更新:正如 Blaisorblade 所指出的,标准库实际上有一个内置方法:unzip3,这就像unzip,但用于三元组而不是对:

    val (l1, l2, l3) = tuples.unzip3
    

    不用说,与我上面的手动解决方案相比,您应该更喜欢这种方法(但对于 arity > 3 的元组,这仍然适用)。

    【讨论】:

    • 太慢了 :) 即将发布:tuples.map{t => t._1 :: t._2 :: t._3 :: Nil}.transpose 不错。 +1
    • 坏主意,你应该使用其他答案的解压缩:stackoverflow.com/a/17281359/53974
    • @Balisorblade:我不同意。如果它是Tuple2,这将是正确的,但它是Tuple3unzip 只处理解压缩对,jeshan 自己的示例显示了Tuple3 的列表,而不是Tuple2
    • @RégisJean-Gilles:所以你需要 unzip3。确实很遗憾(或错误)只支持对和三元组 - shapeless 支持,但对于 HList (docs.typelevel.org/api/shapeless/stable/1.2.4/doc_2.10/…)。
    • 另外,您可以使用tuple.productIterator.toList 将元组转换为(任意的)列表。所以:def unzip(l: List[Product]) = (l map (_.productIterator.toList)).transpose
    【解决方案2】:

    你要解压:

    scala> val (numbers, homonyms) = List(("one", "won"), ("two", "too")).unzip
    numbers: List[java.lang.String] = List(one, two)
    homonyms: List[java.lang.String] = List(won, too)
    

    【讨论】:

    • 这仅适用于pair,不适用于任何其他类型的元组
    • 三元组有 unzip3。
    【解决方案3】:

    如果你想要一些可以用于任意元组大小的东西:

    val tupleSize = 3
    0.until(tupleSize).toList
        .map(x => (_:Product).productElement(x).asInstanceOf[String])
        .map(tuples.map(_))
    

    显然,如果你有一个数组列表,这可以更优雅地表达。

    【讨论】:

    • 或者简单地说:tuples.map(_.productIterator.toList).transpose.asInstanceOf[List[List[String]]。我打算发布这个解决方案,但演员阵容很遗憾。
    • 我也想过那个解决方案,但是这个版本可能比转置更有效。如果我们将ListArrays 作为输入,则可以避免强制转换。
    • @jeshan:使用 _1、_2、_3 的解决方案具有无需运行时强制转换即可正确键入的优点。当使用上面的 productIterator 或 produxtElement 时,您返回的内容被键入为Any,因此需要强制转换。
    • 真正的解决方案当然是使用shapeless
    • 真正的解决办法是不使用元组
    【解决方案4】:

    您可以将语句写在一行中。

    喜欢

     (list1, list2, list3) = tuples.foldRight((List[String](), List[String](), List[String]()))( (a,b) => (a._1 :: b._1, a._2 :: b._2, a._3 :: b._3 ) )
    

    【讨论】:

      【解决方案5】:

      我不知道优雅,但您可以在一行中完成,而无需存储元组的中间步骤。也许它有点难以阅读......

      (for(split <- listOfStrings.map(_.split(":")))
        yield List(split(0), split(1), split(2))).transpose
      

      repl 示例:

      scala> listOfStrings
      res1: List[java.lang.String] = List(a:b:c, d:e:f, g:h:i)
      
      scala> (for(split <- listOfStrings.map(_.split(":")))
           |   yield List(split(0), split(1), split(2))).transpose
      res2: List[List[java.lang.String]] = List(List(a, d, g), List(b, e, h), List(c, f, i))
      

      【讨论】:

        猜你喜欢
        • 2015-02-13
        • 2013-01-21
        • 2018-07-20
        • 1970-01-01
        • 2018-08-03
        • 2014-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多