根据common元素折叠集合列表

时间:2016-11-24 14:06:22

标签: scala functional-programming set

我有一些看起来像一个容易解决的问题,我想用Scala在功能上解决,但无法弄明白。 我正在学习Scala,并希望确保使用函数式编程原理完成它。下面的代码片段(甚至不起作用......)是我管理的所有内容 它仍然有一个可变的变量...... 任何帮助表示赞赏。

基本上我有一个集合列表,我想加入所有具有共同元素的集合。 并递归地应用它,即继续加入列表中的集合,直到它们只剩下脱节。

所以输入 List(Set(1,2,3), Set(4,1,5), Set(6,2,7), Set(8,9))我想获得List(Set(1,2,3,4,5,6,7), Set(8,9))

我的代码如下 - 再次它没有完全发挥作用。

    def mergeSets(sets: List[Set[Int]]): List[Set[Int]] = {
        @tailrec
        def go(list: List[Set[Int]], result: List[Set[Int]]): List[Set[Int]] = list match {
          case Nil => result
          case h :: t => {
            var tmpResult = result
            tmpResult = list.filter(_.intersect(h).nonEmpty).map(_ ++ h) ::: result
            tmpResult = list.filter(_.intersect(h).isEmpty) ::: tmpResult
            go(t, tmpResult.toSet.toList)
          }
        }
        go(sets, List())
      }

2 个答案:

答案 0 :(得分:1)

我会使用元组返回类型而不是List,因为您希望该位置具有含义。我在下面使用的策略是折叠每个集合,对于每个集合,如果有另一个集合具有任何公共元素,则添加到第一个元组位置,否则添加到第二个元组。

def mergeSets(sets: Set[Int]*): (Set[Int], Set[Int]) = {
  sets.foldLeft((Set.empty[Int], Set.empty[Int])) { case ((c, d), n) =>
    if (sets.exists(s => n.exists(s.contains) && s != n))
      (c ++ n, d)
    else
      (c, d ++ n)
  }
}

val (common, disjointed) = mergeSets(Set(1,2,3), Set(4,1,5), Set(6,2,7), Set(8,9))

println(common)
// Set(5, 1, 6, 2, 7, 3, 4)


println(disjointed)
// Set(8, 9)

答案 1 :(得分:1)

这是“一线”解决方案,它结合了更高阶的函数来获得所需的结果:

val l = val l = List(Set(1,2,3), Set(4,1,5), Set(6,2,7), Set(8,9))
(for (el <- l) yield 
     l.foldLeft(el)((s, x) =>
            if (s.intersect(x).size > 0) s.union(x) else s)
).toSet

主要思想是迭代每一组,并产生所有适当集合的联合。这里唯一的技巧是使用toSet来删除重复项。