繁体   English   中英

在 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 的回答很好地涵盖了您问题的“编码”解决方案,因此我不打算详细介绍。 我唯一想补充的是澄清为什么需要你和 jwvh 找到的解决方案。

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

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

并跟进:

Product2是 2 个分量的笛卡尔积。

...这意味着Tuple2[T1,T2]代表:

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

另一方面, 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的初始参数)作为累加器开始

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

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

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

为什么不是List

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM