Scala:Seq.distinctOn函数的实现

Chu*_*ucK 2 scala scala-collections

我正在尝试为一个序列实现一个distinctOn函数,该函数将接受一个函数f并返回一个序列,当f应用于f时,每个项目都有一个不同的结果.例如:

case class Person(name:String, age:Int)

val people = Seq(Person("Al", 20), Person("Bob", 21), 
                 Person("Bob", 24)).distinctOn(_.name)

//people should be:

Seq(Person("Al", 20), Person("Bob", 21))
Run Code Online (Sandbox Code Playgroud)

返回第一个副本(Al)的位置,并保留顺序.我当前的实现包含一个var,而我使用Sets和GroupBy的其他尝试都没有保留顺序.有没有var的更好的方法来实现它?为了记录,我目前的尝试是:

  def distinctOn[A](f: T => A):Seq[T]={
    var seen = Set[A]()

    seq.foldLeft(Seq[T]()) { (res, curr) => {
      if(!seen.contains(f(curr))){
        seen = seen ++ Set[A](f(curr))
        res ++ Seq(curr)
      }else{
        res
      }
    }}
  }
Run Code Online (Sandbox Code Playgroud)

Jea*_*let 6

下面是它保留顺序如适用,也适用于其他的实现Traversable总比Seq秒.它基于其他集合方法中distinct使用的构建器工厂(也称为CanBuildFroms)的实现和使用.

class TraversableOnceExt[A, CC[A] <: TraversableOnce[A]](coll: CC[A]) {
  import collection.generic.CanBuildFrom
  def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[CC[A], A, That]): That = {
    val b = cbf(coll)
    val seen = collection.mutable.HashSet[B]()
    for (x <- coll) {
      val v = f(x)
      if (!seen(v)) {
        b += x
        seen += v
      }
    }
    b.result
  }
}

implicit def commomExtendTraversable[A, C[A] <: TraversableOnce[A]](coll: C[A]): TraversableOnceExt[A, C] =
  new TraversableOnceExt[A, C](coll)
Run Code Online (Sandbox Code Playgroud)