【问题标题】:Collapse the list of sets based on common element折叠基于公共元素的集合列表
【发布时间】:2016-11-24 14:06:22
【问题描述】:

我有一些看起来很简单的问题,我想使用 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())
      }

【问题讨论】:

  • 用空列表替换 Nil:List() 这是经典错误。尝试没有复杂类型的简单逻辑,如 List[Set[Int]]。您是否尝试在 scala 工作表中执行此操作???
  • @PavelOliynyk List() 而不是 Nil 是一个很好的提示,但不会改变结果。我已经制定了简单的案例,因为我可以加入单个集合,只是努力将它们放在一起以处理它们的序列(例如 List[Set[Int]])
  • 随意展示代码示例,只要您继续前进,这些示例就无法正常工作。这就是这个论坛的目的。只需更新原始故事。
  • @PavelOliynyk 不确定您的意思,我已将无法完全运行的代码放在上面。我也可以包含一些 ScalaTest 案例。
  • 首先检查 api:scala-lang.org/api/2.12.0/scala/collection/Set.html 列表顶部有一个非常好的方法可以使用。

标签: scala functional-programming set


【解决方案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 来删除重复项。

【讨论】:

  • 我喜欢这个解决方案,看起来很聪明。正在寻找使用 foldLeft 或 reduceLeft 的东西,因为我觉得你可以这样做。非常感谢
【解决方案2】:

我会使用元组返回类型而不是 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)

【讨论】:

  • 感谢您的宝贵时间。它没有完全产生我预期的结果,因为可能有多个公共或不相交的集合,但它可能可以修改为以这种方式工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
  • 1970-01-01
  • 2020-06-19
  • 2020-04-12
相关资源
最近更新 更多