将列表中的一个元素与所有其他元素进行比较

3

假设我有一个Scala列表,

val list : List[Set[Int]] = List(set1, set2, set3, set4)

我的列表中的每个元素都是一组整数。

我正在寻找一种优雅的方法来创建一个列表,其中我的列表的每个元素都与所有其他元素进行比较。例如,我可能想要生成一个列表,其中每个元素(集合)仅包含不包含在列表中任何其他元素中的元素。

例如:我有一些函数:

def f(element : Set[Int], rest_of_list : List[Set[Int]]) : Set[Int]

我希望能够实现类似于list.map(f(_, rest_of_list))的功能,但不需要为每个元素构建rest_of_list。目前我能想到的唯一方法是使用slice,但我认为这样非常丑陋和低效。

2个回答

2
您可以使用diff代替slice:
 list.map(set => set diff (list diff List(set)).flatten.toSet)
 //Alternative with filterNot
 list.map(set => set.filterNot((list diff List(set)).flatten.contains))  

diff 在这里起作用,因为它只会删除一个元素实例,而 Set[Int] 具有一个很好的 equals 方法:

List(Set(1), Set(1, 2)) diff List(Set(1)) //List(Set(1, 2))
List(Set(1), Set(1)) diff List(Set(1)) //List(Set(1))

因此,将一个集合映射到列表中的所有其他集合:
val setWithOthers = list.map(set => set -> (list diff List(set)))
val setWithOthers = (list, list.map(list diff List(_))).zipped.toList //equivalent, less efficient

如果你想在list的元素上映射函数f,你可以这样做:

setsWithOthers.map { case(set, others) => f(set, others) }
setsWithOthers.map(kvp => f(kvp._1, kvp._2))
setsWithOthers.map((f _).tupled)

您还可以创建完整的多重集合,以跟踪每个元素出现的次数。 然后,在循环的每次迭代中,您可以从完整的多重集合中“减去”一个集合:

val multiset = list.flatten.groupBy(identity).mapValues(_.length)

这比使用切片要漂亮得多,但仍不是我所希望的。 (我的失望针对的是Scala,而不是你的答案) - Ritwik Bose
你更新了你的答案,提供了一个比我想象中更好的版本。使用 map 方法是我要采纳的答案。 - Ritwik Bose

1
我不知道它是否像您想要的那样优雅,但有一种更通用的方法可以将“f”替换为任何内容:
val list = List(Set(1,2,3,4),Set(1,2),Set(1,3))

list.map(e => f(e,list.filterNot(_==e)))
//res0: List[Set[Int]] = List(Set(4), Set(), Set())

def f(element : Set[Int], rest_of_list : List[Set[Int]]) : Set[Int] = {
  (element.toList diff rest_of_list.flatten.toList).toSet
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接