Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 元组从列表中消除重复_Scala_Duplicate Removal_Performance - Fatal编程技术网

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