如何展开一个嵌套的元组?

25

我有一个嵌套元组结构,类似于(String,(String,Double)),我想将其转换为(String,String,Double)。 我有各种各样的嵌套元组,并且不想手动转换每个元组。 有没有方便的方法可以实现这一点?

5个回答

25

13
你应该提供一些代码示例,仅提供链接的回答不符合 StackOverflow 的指南。 - Juh_
1
@Juh_ 点击这里查看代码示例。 - jack

10

元组中没有 flatten 方法。但是如果您知道其结构,可以执行以下操作:

implicit def flatten1[A, B, C](t: ((A, B), C)): (A, B, C) = (t._1._1, t._1._2, t._2)
implicit def flatten2[A, B, C](t: (A, (B, C))): (A, B, C) = (t._1, t._2._1, t._2._2)

这将使任意类型的元组扁平化。你也可以在定义中添加implicit关键字。这仅适用于三个元素。你可以像这样扁平化元组:

(1, ("hello", 42.0))   => (1, "hello", 42.0)
(("test", 3.7f), "hi") => ("test", 3.7f, "hi")

多重嵌套的元组无法完全展开,因为返回类型中只有三个元素:

((1, (2, 3)),4)        => (1, (2, 3), 4)

2

我不确定这样做的效率如何,但你可以使用tuple.productIterator.toListTuple转换为List,然后展开嵌套的列表:

scala> val tuple = ("top", ("nested", 42.0))
tuple: (String, (String, Double)) = (top,(nested,42.0))

scala> tuple.productIterator.map({
     |   case (item: Product) => item.productIterator.toList
     |   case (item: Any) => List(item)
     | }).toList.flatten
res0: List[Any] = List(top, nested, 42.0)

1
不幸的是,使用这种方法,您将失去元素的静态类型。 - DBear

1

上面答案的补充的补集

粘贴此实用代码:

import shapeless._
import ops.tuple.FlatMapper
import syntax.std.tuple._
trait LowPriorityFlatten extends Poly1 {
  implicit def default[T] = at[T](Tuple1(_))
}
object flatten extends LowPriorityFlatten {
  implicit def caseTuple[P <: Product](implicit lfm: Lazy[FlatMapper[P, flatten.type]]) =
    at[P](lfm.value(_))
}

然后您就可以展平任何嵌套的元组:
scala> val a = flatten(((1,2),((3,4),(5,(6,(7,8))))))
a: (Int, Int, Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6,7,8)

Note that this solution does not work for self-defined case class type, which would be converted to String in the output.

scala> val b = flatten(((Cat("c"), Dog("d")), Cat("c")))
b: (String, String, String) = (c,d,c)

0

在我看来,简单的模式匹配就可以解决问题。

scala> val motto = (("dog", "food"), "tastes good")
val motto: ((String, String), String) = ((dog,food),tastes good)

scala> motto match {
     | case ((it, really), does) => (it, really, does)
     | }
val res0: (String, String, String) = (dog,food,tastes good)

或者如果您有一组这样的元组:

scala> val motto = List(
     | (("dog", "food"), "tastes good")) :+ (("cat", "food"), "tastes bad")
val motto: List[((String, String), String)] = List(((dog,food),tastes good), ((cat,food),tastes bad))

scala> motto.map {
     | case ((one, two), three) => (one, two, three)
     | }
val res2: List[(String, String, String)] = List((dog,food,tastes good), (cat,food,tastes bad))

我认为即使有多种情况,这也会很方便。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接