Scala:使用groupBy,mapValues和filter过滤重复的名称?

时间:2013-10-14 14:52:33

标签: scala

这应该很简单,我想,但我无法让它发挥作用。我有一个带有属性名称的案例类。我想查看它们中是否有重复的名称......

employees.groupBy(_.name).mapValues(_.size).filter(_._2 == 1).toSeq.isEmpty

这不起作用......应该吗?

3 个答案:

答案 0 :(得分:4)

其他答案可行,但groupBy是一项昂贵的操作,如果您有10,000名员工且前两名具有相同名称,则效率低下。

1)简短方法 :( distinct在内部构建所有值的HashSet)

val names = employees.map(_.name)
names.distinct != names

2)高效方法 :(在查找重复之前,只需遍历所需的seq)

def hasDupes(employees: Seq[Employee]): Boolean = {
  val names = collection.mutable.Set.empty[String]
  employees.foreach { e => 
    if (names(e.name)) return true
    names += e.name
  }
  false
}

你可以使用尾递归方法将它写成one-liner,但事实是不可变集比可变集快得多,所以如果我们想提高效率那就不好了。

3)离墙式方法 :(根本没有构建一个集合,但是一旦发现两个名称相同,就会启动快速排序并退出(通过便宜的例外)应该是有效的。)

class Dupe extends Throwable with util.control.NoStackTrace
val dupeOrd = new Ordering[Employee] {
  def compare(x: Employee, y: Employee) =
    if (x.name == y.name) throw new Dupe else x.name compare y.name
}
def hasDupes(employees: Seq[Employee]) =
  try { employees.sorted(dupeOrd); false } catch { case e: Dupe => true }
结果的

基准,方法0为om-nom-nom的groupBy一个,(1000个员工Vector上1000次运行的毫秒数,没有重复项):

method             time  Early return if duplicate found
0  (groupBy)       1560  No
1  (distinct)      329   No
2a (mutable.Set)   255   Yes
2b (immutable.Set) 1414  Yes
3  (sorting)       666   Yes        //242 if employees already in name order

答案 1 :(得分:2)

也许你想要:

case class Employee(name: String)
val bob = Employee("Bob")
val joe = Employee("Joe")

def haveDupes(emps: Seq[Employee]) =  emps.groupBy(_.name).exists {
 case (name, group) => group.size > 1
}

scala> haveDupes(Seq(bob))
res11: Boolean = false

scala> haveDupes(Seq(bob, bob))
res12: Boolean = true

scala> haveDupes(Seq(bob, joe))
res13: Boolean = false

scala> haveDupes(Seq(bob, joe, bob))
res14: Boolean = true

答案 2 :(得分:0)

因为这里

employees.groupBy(_.name).mapValues(_.size).filter(_._2 == 1).toSeq.isEmpty

您不需要==但是>登录

employees.groupBy(_.name).mapValues(_.size).filter(_._2 > 1).toSeq.isEmpty

首先你将groupBy返回一组元组(K,V),然后你映射每一个以查看每个有mapValues(_。size)的数量,然后你想要检查是否有任何元组大小大于大于1的记录。