删除列表中指定相等功能的重复项

Joh*_*son 15 scala

我有一个List[A],如果给出一个相等的函数,如何删除重复的惯用方法(a:A, b:A) => Boolean?我一般不能覆盖equalsA

我现在想的方法是创建一个class AExt覆盖的包装equals,然后

list.map(新的AExt(_)).distinct

但我想知道是否有更清洁的方式.

小智 20

有一种简单(简单)的方法可以做到这一点:

list.groupBy(_.key).mapValues(_.head)
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以通过替换_.head功能块立即使用生成的地图,如:

sameElements => { val observedItem = sameElements.head
                  new A (var1 = observedItem.firstAttr,
                         var2 = "SomethingElse") }
Run Code Online (Sandbox Code Playgroud)

A为每个不同的元素返回一个新元素.

只有一个小问题.上面的代码(list.groupBy(_.key).mapValues(_.head))没有很好地解释删除重复的意图.因此,拥有像distinctIn[A](attr: A => B)或的函数会很棒distinctBy[A](eq: (A, A) -> Boolean).

  • 这样,结果将是唯一键上的映射.要获得不同的值,应该.map(_._ 2.head) (8认同)

drs*_*ens 7

使用FoocustomEquals来自misingFaktor的答案:

  case class Foo(a: Int, b: Int)
  val (a, b, c, d) = (Foo(3, 4), Foo(3, 1), Foo(2, 5), Foo(2, 5))
  def customEquals(x: Foo, y: Foo) = x.a == y.a

  (Seq(a, b, c, d).foldLeft(Seq[Foo]()) {
    (unique, curr) => {
      if (!unique.exists(customEquals(curr, _)))
        curr +: unique
      else
        unique
    }
  }).reverse
Run Code Online (Sandbox Code Playgroud)

如果结果排序很重要但要删除的副本不重要,则foldRight更可取

  Seq(a, b, c, d).foldRight(Seq[Foo]()) {
    (curr, unique) => {
      if (!unique.exists(customEquals(curr, _)))
        curr +: unique
      else
        unique
    }
  }
Run Code Online (Sandbox Code Playgroud)


oxb*_*kes 4

我必须说,我想我会通过一个中间集合,如果Set你期望你的Lists 可能会很长,因为测试a 上的存在(通过exists或)当然是O(n) :findSeq

而不是写一个自定义的equals;决定元素的相等属性所以而不是:

def myCustomEqual(a1: A, a2: A) = a1.foo == a2.foo && a1.bar == a2.bar
Run Code Online (Sandbox Code Playgroud)

制作一把钥匙。就像这样:

type Key = (Foo, Bar)
def key(a: A) = (a.foo, a.bar)
Run Code Online (Sandbox Code Playgroud)

然后你可以将这些键添加到 a 中Set,看看你以前是否遇到过它们。

var keys = Set.empty[Key]
((List.empty[A] /: as) { (l, a) => 
  val k = key(a)
  if (keys(k)) l else { keys += k; a +: l  }
}).reverse
Run Code Online (Sandbox Code Playgroud)

当然,在列表非常短的情况下,该解决方案的空间复杂度更差,并且性能可能更差(因为您正在创建额外的对象 - 键)。如果您不喜欢var折叠中的 ,您可能想看看如何使用scalaz 7 来实现State一点Traverse