功能编程:列表是否仅包含唯一项?

时间:2010-10-06 10:19:19

标签: language-agnostic scala functional-programming

我有一份未分类的清单,想知道其中的所有项目是否都是唯一的 我的天真方法是

val l = List(1,2,3,4,3)
def isUniqueList(l: List[Int]) = (new HashSet()++l).size == l.size

基本上,我正在检查包含列表中所有元素的Set是否具有相同的大小(因为在原始列表中出现两次的项目只会在集合中出现一次),但我不确定这是否是这个问题的理想解决方案。

修改: 我对3个最受欢迎的解决方案进行了基准测试,l==l.distinctl.size==l.distinct.size和Alexey基于HashSet的解决方案。 每个函数运行1000次,包含10个项目的唯一列表,10000个项目的唯一列表以及第三个季度中出现的一个项目复制到列表中间的相同列表。在每次运行之前,每个函数都被调用1000次来预热JIT,整个基准测试在使用System.currentTimeMillis之前运行了5次。 这台机器是C2D P8400(2.26 GHz),内存为3GB,java版本是OpenJDK 64位服务器VM(1.6.0.20)。 java args是-Xmx1536M -Xms512M

结果:

l.size==l.distinct.size (3, 5471, 2, 6492)
l==l.distinct           (3, 5601, 2, 6054)
Alexey's HashSet        (2, 1590, 3, 781)

较大对象的结果(字符串从1KB到5KB):

l.size==l.distinct.size MutableList(4, 5566, 7, 6506)
l==l.distinct           MutableList(4, 5926, 3, 6075)
Alexey's HashSet        MutableList(2, 2341, 3, 784)

使用HashSets的解决方案肯定是最快的,正如他已经指出的那样使用.size并没有产生重大影响。

3 个答案:

答案 0 :(得分:15)

这是我能想到的最快的纯功能解决方案:

def isUniqueList(l: List[T]) = isUniqueList1(l, new HashSet[T])

@tailrec
def isUniqueList1(l: List[T], s: Set[T]) = l match {
  case Nil => true
  case (h :: t) => if (s(h)) false else isUniqueList1(t, s + h)
}

这应该更快,但使用可变数据结构(基于Vasil Remeniuk给出的distinct实现):

def isUniqueList(l: List[T]): Boolean = {
  val seen = mutable.HashSet[A]()
  for (x <- this) {
    if (seen(x)) {
      return false
    }
    else {
      seen += x
    }
  }
  true
}

这是最简单的(相当于你的):

def isUniqueList(l: List[T]) = l.toSet.size == l.size

答案 1 :(得分:6)

我只想使用distinct方法:

scala> val l = List(1,2,3,4,3)
l: List[Int] = List(1, 2, 3, 4, 3)

scala> l.distinct.size == l.size
res2: Boolean = false


ADD Standard distinct implementation(来自scala.collection.SeqLike)使用可变的HashSet来查找重复的元素:

  def distinct: Repr = {
    val b = newBuilder
    val seen = mutable.HashSet[A]()
    for (x <- this) {
      if (!seen(x)) {
        b += x
        seen += x
      }
    }
    b.result
  }

答案 2 :(得分:2)

更有效的方法是尝试找到一个骗子;如果找到一个,这会更快地返回:

var dupes : Set[A] = Set.empty

def isDupe(a : A) = if (dupes(a)) true else { dupes += a; false }

//then
l exists isDupe