我有for-comprehension
来自Set[MyType]
的生成器
这个MyType
有一个名为lazy val
的{{1}}变量,它返回一对集合:
(设置[MyFact],设置[MyFact])。
我希望循环遍历所有这些并将事实统一到一个扁平对(设置[MyFact],设置[MyFact]),如下所示,但是我收到factsPair
和No implicit view available ...
错误。 (我对Scala有点新意,所以仍然试图习惯这些错误)。
not enough arguments for flatten: implicit (asTraversable ...
我需要指定什么才能使其变平?
答案 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对元组和集合的隐式幺半群。