在Scala中展平元组列表?

时间:2016-05-11 07:22:06

标签: list scala tuples flatten

我原本以为可以很容易地将元组列表弄平:

scala> val p = "abcde".toList
p: List[Char] = List(a, b, c, d, e)

scala> val q = "pqrst".toList
q: List[Char] = List(p, q, r, s, t)

scala> val pq = p zip q
pq: List[(Char, Char)] = List((a,p), (b,q), (c,r), (d,s), (e,t))

scala> pq.flatten

但相反,会发生这种情况:

<console>:15: error: No implicit view available from (Char, Char) => scala.collection.GenTraversableOnce[B].
       pq.flatten
          ^

我可以完成工作:

scala> (for (x <- pq) yield List(x._1, x._2)).flatten
res1: List[Char] = List(a, p, b, q, c, r, d, s, e, t)

但我不理解错误信息。而我的替代解决方案似乎错综复杂且效率低下。

该错误消息的含义是什么?为什么我不能简单地展平元组列表?

3 个答案:

答案 0 :(得分:12)

如果无法找到隐式转化,您可以明确提供。

pq.flatten {case (a,b) => List(a,b)}

如果在整个代码中多次执行此操作,则可以通过隐藏来保存一些样板文件。

scala> import scala.language.implicitConversions
import scala.language.implicitConversions

scala> implicit def flatTup[T](t:(T,T)): List[T]= t match {case (a,b)=>List(a,b)}
flatTup: [T](t: (T, T))List[T]

scala> pq.flatten
res179: List[Char] = List(a, p, b, q, c, r, d, s, e, t)

答案 1 :(得分:4)

jwvh的答案涵盖&#34;编码&#34;完全解决你的问题,所以我不打算详细介绍。我想要添加的唯一内容是澄清为什么您和jwvh都需要的解决方案。

如Scala图书馆所述,Tuple2(,)转换为)是:

  

2个元素的元组; Product2的规范表示。

跟进:

  

Product2是2个组件的笛卡尔积。

... Tuple2[T1,T2]代表的means

  

所有可能的元素对的集合,其组件是两个集合的成员(分别为T1T2中的所有元素)

另一方面,List[T]表示T元素的有序集合。

所有这一切实际上意味着没有绝对的方式将任何可能的Tuple2[T1,T2]转换为List[T] ,只是因为 T1T2可能不同。例如,采用以下元组:

val tuple = ("hi", 5)

这样的元组怎么可能被夷为平地? 5应该String吗?或者可能只是展平到List[Any]?虽然可以使用这两种解决方案,但它们围绕类型系统工作,因此它们不是按照设计在Tuple API中编码的。

所有这一切都归结为这种情况没有默认的隐式视图,你必须自己提供一个,因为 jwvh 并且你已经想到了。

答案 2 :(得分:0)

我们最近需要这样做。在介绍我们的解决方案之前,请允许我简要解释一下用例。

给定一个项目池(我将其称为类型 T),我们希望针对池中的所有其他项目对每个项目进行评估。这些比较的结果是 Set失败的评估,我们将其表示为所述评估中左项和右项的元组:(T, T)

一旦这些评估完成,我们就可以将 Set[(T, T)] 展平为另一个 Set[T],突出显示所有未通过任何比较的项目。

我们对此的解决方案是折叠:

val flattenedSet =
    set.foldLeft(Set[T]())
                { case (acc, (x, y)) => acc + x + y }

这以一个空集(foldLeft 的初始参数)作为累加器开始。

然后,对于这里消耗的Set[(T, T)](命名为set)中的每个元素,都会传递fold函数:

  1. 累加器的最后一个值 (acc),以及
  2. 该元素的 (T, T) 元组,case 将其解构为 xy

我们的 fold 函数然后返回 acc + x + y,它返回一个包含累加器中除 xy 之外的所有元素的集合。该结果作为累加器传递给下一次迭代——因此,它累加每个元组内的所有值。

我特别喜欢这个解决方案,因为它避免在进行展平时创建中间 List - 相反,它在构建新的 Set[T] 时直接解构每个元组。

我们也可以更改我们的评估代码,以返回包含每次失败评估中左右项目的 List[T] - 那么 flatten 就是 Just Work™。但我们认为元组更准确地代表了我们的评估目标——特别是一个项目与另一个项目的对比,而不是可以想象代表任意数量项目的开放式类型。