将一组对集合为一对集合

时间:2013-11-15 16:09:36

标签: scala flatten for-comprehension

我有for-comprehension来自Set[MyType]的生成器 这个MyType有一个名为lazy val的{​​{1}}变量,它返回一对集合: (设置[MyFact],设置[MyFact])。

我希望循环遍历所有这些并将事实统一到一个扁平对(设置[MyFact],设置[MyFact]),如下所示,但是我收到factsPairNo implicit view available ...错误。 (我对Scala有点新意,所以仍然试图习惯这些错误)。

not enough arguments for flatten: implicit (asTraversable ...

我需要指定什么才能使其变平?

4 个答案:

答案 0 :(得分:3)

Scala flatten适用于相同类型。你有一个Seq [(Set [MyFact],Set [MyFact])],它不会被夷为平地。

我建议您学习foldLeft功能,因为它非常通用,并且只要您掌握它就很容易使用:

lazy val allFacts = myTypeList.foldLeft((Set[MyFact](), Set[MyFact]())) {
  case (accumulator, next) =>
    val pairs1 = accumulator._1 ++ next.factsPair._1
    val pairs2 = accumulator._2 ++ next.factsPair._2
    (pairs1, pairs2)
}

第一个参数采用它将附加其他元素的初始元素。我们从一个空的Tuple[Set[MyFact], Set[MyFact]]开始,如下所示:(Set[MyFact](), Set[MyFact]())

接下来,我们必须指定获取累加器的函数,并将下一个元素追加到它,并返回包含其中下一个元素的新累加器。由于所有的元组,它看起来并不好,但是很有效。

答案 1 :(得分:1)

您将无法使用flatten,因为集合上的flatten会返回一个集合,而元组不是集合。

当然,你可以分开,拼合,再加入:

val pairs = for {
  mytype <- mytypeList
} yield mytype.factsPair
val (first, second) = pairs.unzip
val allFacts = (first.flatten, second.flatten)

答案 2 :(得分:0)

一个元组是不可克服的,所以你不能压扁它。您需要返回可以迭代的内容,例如List:

List((1,2), (3,4)).flatten          // bad
List(List(1,2), List(3,4)).flatten  // good

答案 3 :(得分:0)

我想提供更多的代数观点。你可以使用monoids很好地解决你的问题。对于每个monoid,都有一个零元素和一个将两个元素合并为一个元素的操作。

在这种情况下,设置为monoid:零元素是空集,操作是并集。如果我们有两个幺半群,他们的笛卡尔积也是一个幺半群,其中操作是成对定义的(见examples on Wikipedia)。

Scalaz为集合和元组定义了monoids,因此我们不需要在那里做任何事情。我们只需要一个将多个monoid元素组合成一个的辅助函数,使用折叠可以轻松实现:

def msum[A](ps: Iterable[A])(implicit m: Monoid[A]): A =
  ps.foldLeft(m.zero)(m.append(_, _))

(也许在Scala中已经存在这样的功能,我没有找到它)。使用msum我们可以轻松定义

def pairs(ps: Iterable[MyType]): (Set[MyFact], Set[MyFact]) =
  msum(ps.map(_.factsPair))

使用Scalaz对元组和集合的隐式幺半群。