展平 Scala 中的元组列表?

Flatten a list of tuples in Scala?

我本以为元组列表可以很容易地展平:

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)

但是我不明白错误信息。我的替代解决方案似乎很复杂且效率低下。

该错误消息是什么意思,为什么我不能简单地展平元组列表?

如果找不到隐式转换,您可以显式提供。

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)

jwvh 的回答很好地涵盖了 "coding" 对您问题的解决方案,因此我不打算对此进行更多详细介绍。我唯一想补充的是澄清为什么需要你和 jwvh 找到的解决方案。

如 Scala 库中所述,Tuple2(,) 转换为)是:

A tuple of 2 elements; the canonical representation of a Product2.

并跟进:

Product2 is a cartesian product of 2 components.

...Tuple2[T1,T2]代表哪个means

The set of all possible pairs of elements whose components are members of two sets (all elements in T1 and T2 respectively).

另一方面,

A List[T] 表示 T 元素的有序集合。

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

val tuple = ("hi", 5)

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

所有这一切都归结为这样一个事实,即在这种情况下没有默认的隐式视图,您必须自己提供一个,因为 jwvh 并且您已经知道了。

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

用例

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

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

解决方案

我们的解决方案是弃牌:

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

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

然后,这里对consumedSet[(T, T)](命名为set)中的每个元素,传递fold函数:

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

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

为什么不 Lists?

我特别欣赏这个解决方案,因为它避免了在进行扁平化时创建中间 List——相反,它在构建新的 Set[T].

时直接解构每个元组

我们也可以将我们的评估代码更改为 return List[T]s,其中包含每个失败评估中的左侧和右侧项目——然后 flatten 就可以工作™。但是我们认为元组更准确地表示了我们要进行评估的目的——特别是一个项目与另一个项目的对比,而不是可以想象地表示任意数量项目的开放式类型。