Scala 元组从列表中消除重复
考虑以下元组列表:Scala 元组从列表中消除重复,scala,duplicate-removal,performance,Scala,Duplicate Removal,Performance,考虑以下元组列表: val input= List((A,B), (C,B), (B,A)) 假设元素(A,B)和(B,A)是相同的,因此是重复的,从上面的列表中消除重复的有效方法是什么(最好是在Scala中)。这意味着所需的输出是另一个列表: val deduplicated= List((A,B), (C,B)) 提前谢谢 p、 s:这不是家庭作业;) 更新: 谢谢大家
val input= List((A,B),
(C,B),
(B,A))
假设元素(A,B)
和(B,A)
是相同的,因此是重复的,从上面的列表中消除重复的有效方法是什么(最好是在Scala中)。这意味着所需的输出是另一个列表:
val deduplicated= List((A,B),
(C,B))
提前谢谢
p、 s:这不是家庭作业;)
更新:
谢谢大家!“set”解决方案似乎是更好的解决方案。您可以使用set进行尝试,但需要声明自己的tuple类才能使其工作
case class MyTuple[A](t: (A, A)) {
override def hashCode = t._1.hashCode + t._2.hashCode
override def equals(other: Any) = other match {
case MyTuple((a, b)) => a.equals(t._1) && b.equals(t._2) || a.equals(t._2) && b.equals(t._1)
case _ => false
}
}
val input= List(("A","B"),
("C","B"),
("B","A"))
val output = input.map(MyTuple.apply).toSet.toList.map((mt: MyTuple[String]) => mt.t)
println(output)
编辑:
特拉维斯的回答让我意识到有一种更好的方法可以做到这一点。这是通过编写一个类似于sortBy的distinctBy方法来实现的
implicit class extList[T](list: List[T]) {
def distinctBy[U](f: T => U): List[T] = {
var set = Set.empty[U]
var result = List.empty[T]
for(t <- list) {
val u = f(t)
if(!set(u)) {
result ::= t
set += u
}
}
result.reverse
}
}
println(input.distinctBy { case (a, b) => Set((a,b), (b,a)) })
隐式类extList[T](list:list[T]){
def distinctBy[U](f:T=>U):列表[T]={
var set=set.empty[U]
var result=List.empty[T]
对于(t集((a,b),(b,a))})
在与SpiderPig的答案相同的行上,这里有一个不使用集合的解决方案(因为遍历集合不会保留原始列表的顺序,这可能是一个注释)
范例
val input = List(("A","B"), ("C","B"),("B","A"))
//> input: List[(String, String)] = List((A,B), (C,B), (B,A))
val distinctTuples = input.map(MyPimpedTuple(_)).distinct.map(_.t)
//> distinctTuples: List[(String, String)] = List((A,B), (C,B))
是的,我还建议将集合作为目标数据结构,因为集合查找可能比两个for循环更有效。(对不起,我是clojure的家伙,这肯定不是clojure中最短的版本…)
我们可以使用
集合
跟踪我们已经看到的元素,同时使用过滤器
消除重复:
def removeDuplicates[T](l: List[(T, T)]) = {
val set = scala.collection.mutable.Set[(T, T)]()
l.filter { case t@(x, y) =>
if (set(t)) false else {
set += t
set += ((y, x))
true
}
}
}
当我们找到一个以前从未见过的元组时,我们将它和它以及它的元素交换到集合中。为了完整起见,可以非常简单地通过一个折叠以纯函数的方式来实现这一点(手动定义相等让我感到紧张,我不确定易变性在这里能给你带来多少好处): 这不是很有效,因为它会为每个项目在列表中搜索两次(并附加到列表中),但这并不难解决:
def distinctPairs[A](xs: List[(A, A)]) = xs.foldLeft(
(List.empty[(A, A)], Set.empty[(A, A)])
) {
case (current @ (_, seen), p) if seen(p) => current
case ((acc, seen), p @ (a, b)) => (p :: acc, seen ++ Set((a, b), (b, a)))
}._1.reverse
这两种实现都保持了顺序。还可以考虑依赖于
映射上的唯一键,其中键是一组双工元素
def uniq[A](a: List[(A,A)]) = a.map( t => Set(t._1,t._2) -> t ).toMap.values
不是最有效的,但足够简单;适用于小型集合。非常好且简洁的解决方案!谢谢!这大致是scala库中distinct
的实现,只是您使用了过滤器而不是可变的构建器。
。很好的解决方案。太好了!我正在考虑折叠,bud没有来想出一个解决办法。谢谢!
def distinctPairs[A](xs: List[(A, A)]) = xs.foldLeft(List.empty[(A, A)]) {
case (acc, (a, b)) if acc.contains((a, b)) || acc.contains((b, a)) => acc
case (acc, p) => acc :+ p
}
def distinctPairs[A](xs: List[(A, A)]) = xs.foldLeft(
(List.empty[(A, A)], Set.empty[(A, A)])
) {
case (current @ (_, seen), p) if seen(p) => current
case ((acc, seen), p @ (a, b)) => (p :: acc, seen ++ Set((a, b), (b, a)))
}._1.reverse
def uniq[A](a: List[(A,A)]) = a.map( t => Set(t._1,t._2) -> t ).toMap.values