Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.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 - Fatal编程技术网

在Scala中,如何从列表中删除重复项?

在Scala中,如何从列表中删除重复项?,scala,Scala,如果我有 val dirty = List("a", "b", "a", "c") 是否有返回“a”、“b”、“c”的列表操作查看ScalaDoc的 更新。其他人建议使用Set而不是List。这很好,但是请注意,默认情况下,Set接口不保留元素顺序。您可能希望使用明确保留顺序的集合实现,例如。在使用Kitpon的解决方案之前,考虑使用集合,而不是列表,它确保每个元素都是唯一的 由于大多数列表操作(foreach,map,filter,…)对于集合和列表都是相同的,因此在代码中更改集合可能非常容

如果我有

val dirty = List("a", "b", "a", "c")

是否有返回“a”、“b”、“c”的列表操作查看ScalaDoc的


更新。其他人建议使用
Set
而不是
List
。这很好,但是请注意,默认情况下,
Set
接口不保留元素顺序。您可能希望使用明确保留顺序的集合实现,例如。

在使用Kitpon的解决方案之前,考虑使用
集合
,而不是
列表
,它确保每个元素都是唯一的


由于大多数列表操作(
foreach
map
filter
,…)对于集合和列表都是相同的,因此在代码中更改集合可能非常容易。

首先使用集合当然是正确的方法,但是:

scala> List("a", "b", "a", "c").toSet.toList
res1: List[java.lang.String] = List(a, b, c)

工作。或者只需
toSet
,因为它支持Seq
Traversable
接口

scala.collection.immutable.List现在有了一个
.distinct
方法


因此,现在可以调用
dirty.distinct
,而无需转换为
集合或
Seq

inArr.distinct foreach println

算法方式

def dedupe(str: String): String = {
  val words = { str split " " }.toList

  val unique = words.foldLeft[List[String]] (Nil) {
    (l, s) => {
      val test = l find { _.toLowerCase == s.toLowerCase } 
      if (test == None) s :: l else l
    }
  }.reverse

  unique mkString " "
}
对于已排序的列表 如果您碰巧希望知道列表中的不同项已被排序,正如我经常需要的那样,下面的执行速度大约是
。distinct
的两倍:

  def distinctOnSorted[V](seq: List[V]): List[V] =
    seq.foldLeft(List[V]())((result, v) =>
      if (result.isEmpty || v != result.head) v :: result else result)
    .reverse
0-99之间100000000个随机整数列表的性能结果:

distinct        : 0.6655373s
distinctOnSorted: 0.2848134s
使用可变列表或ListBuffer的性能 虽然看起来更可变/非函数式的编程方法可能比预先设置一个不可变列表要快,但实践表明并非如此。不变的实现始终表现得更好。我猜原因是scala将编译器优化集中在不可变集合上,并且做得很好。(我欢迎其他人提交更好的实施方案。)

实施:

object ListUtil {
  def distinctOnSorted[V](seq: List[V]): List[V] =
    seq.foldLeft(List[V]())((result, v) =>
      if (result.isEmpty || v != result.head) v :: result else result)
    .reverse

  def distinctOnSortedMut1[V](seq: List[V]): Seq[V] = {
    if (seq.isEmpty) Nil
    else {
      val result = mutable.MutableList[V](seq.head)
      seq.zip(seq.tail).foreach { case (prev, next) =>
        if (prev != next) result += next
      }
      result //.toList
    }
  }

  def distinctOnSortedMut2[V](seq: List[V]): Seq[V] = {
    val result = mutable.MutableList[V]()
    if (seq.isEmpty) return Nil
    result += seq.head
    var prev = seq.head
    for (v <- seq.tail) {
      if (v != prev) result += v
      prev = v
    }
    result //.toList
  }

  def distinctOnSortedMut3[V](seq: List[V]): List[V] = {
    val result = mutable.MutableList[V]()
    if (seq.isEmpty) return Nil
    result += seq.head
    var prev = seq.head
    for (v <- seq.tail) {
      if (v != prev) v +=: result
      prev = v
    }
    result.reverse.toList
  }

  def distinctOnSortedMut4[V](seq: List[V]): Seq[V] = {
    val result = ListBuffer[V]()
    if (seq.isEmpty) return Nil
    result += seq.head
    var prev = seq.head
    for (v <- seq.tail) {
      if (v != prev) result += v
      prev = v
    }
    result //.toList
  }
}
objectlistutil{
def DISTINCTONSORDED[V](序列:列表[V]):列表[V]=
seq.foldLeft(List[V]())((result,V)=>
if(result.isEmpty | | v!=result.head)v::result else result)
.反向
def distinctOnSortedMut1[V](序列:列表[V]):序列[V]={
如果(seq.isEmpty)无
否则{
val结果=可变。可变列表[V](序列头)
seq.zip(seq.tail).foreach{case(prev,next)=>
如果(上一个!=下一个)结果+=下一个
}
结果//.toList
}
}
def distinctOnSortedMut2[V](序列:列表[V]):序列[V]={
val result=mutable.MutableList[V]()
如果(seq.isEmpty)返回零
结果+=序号头
var prev=序列头

对于(v,还可以使用递归和模式匹配:

def removeDuplicates[T](xs: List[T]): List[T] = xs match {
  case Nil => xs
  case head :: tail => head :: removeDuplicates(for (x <- tail if x != head) yield x)
}

def removeDuplicates[T](xs:List[T]):List[T]=xs匹配{
案例Nil=>xs

case head::tail=>head::移除的副本(用于(x我编辑了你的答案,因为
Set
实现了
Traversable
,而不是
Seq
。区别在于
Seq
保证了元素的顺序,而
Traversable
没有。如果你有一个文件列表,需要在类似文件名的部分进行比较,该怎么办?@一个有趣的问题。也许最简单的方法是创建一个新的类型
Map[String,File]
,其中键是感兴趣的文件名的一部分。构建映射后,您可以调用
values
方法来获取值的
Iterable
——所有键都将因构造而不同。@KiptonBarros,我想您可以使用
scala.collection.Iterable[A]的成员来实现这一点
。这打印了所需的输出,不是OP要求返回的(大概是列表)?他有一个列表,而不是字符串。这并不能回答问题。
scala.collection.Iterable[a]没有定义distinct
。因此,在这种情况下,您必须使用upgrade
dirty
升级到
Seq
Set
(即使用
.toList
.toSeq
.toSet
成员)这是非常有效的,因为只有100个唯一的值,但是如果使用不可变结构时有更多的值,你会遇到麻烦。为了更快,你可以用可变结构来实现它。@Nick我原本以为也是这样,但是请看上面的编辑。我尝试了上面的myse如果我不明白为什么immutable会更好,但即使您大幅增加不同值的数量,情况仍然如此。我还尝试了一些可变结构,其中prepend更有效,但即使没有在最后反转结果,它也会更慢。
RemovedUpplicates(tail.filter(!=head))
object ListUtil {
  def distinctOnSorted[V](seq: List[V]): List[V] =
    seq.foldLeft(List[V]())((result, v) =>
      if (result.isEmpty || v != result.head) v :: result else result)
    .reverse

  def distinctOnSortedMut1[V](seq: List[V]): Seq[V] = {
    if (seq.isEmpty) Nil
    else {
      val result = mutable.MutableList[V](seq.head)
      seq.zip(seq.tail).foreach { case (prev, next) =>
        if (prev != next) result += next
      }
      result //.toList
    }
  }

  def distinctOnSortedMut2[V](seq: List[V]): Seq[V] = {
    val result = mutable.MutableList[V]()
    if (seq.isEmpty) return Nil
    result += seq.head
    var prev = seq.head
    for (v <- seq.tail) {
      if (v != prev) result += v
      prev = v
    }
    result //.toList
  }

  def distinctOnSortedMut3[V](seq: List[V]): List[V] = {
    val result = mutable.MutableList[V]()
    if (seq.isEmpty) return Nil
    result += seq.head
    var prev = seq.head
    for (v <- seq.tail) {
      if (v != prev) v +=: result
      prev = v
    }
    result.reverse.toList
  }

  def distinctOnSortedMut4[V](seq: List[V]): Seq[V] = {
    val result = ListBuffer[V]()
    if (seq.isEmpty) return Nil
    result += seq.head
    var prev = seq.head
    for (v <- seq.tail) {
      if (v != prev) result += v
      prev = v
    }
    result //.toList
  }
}
import scala.util.Random

class ListUtilTest extends UnitSpec {
  "distinctOnSorted" should "return only the distinct elements in a sorted list" in {
    val bigList = List.fill(1e7.toInt)(Random.nextInt(100)).sorted

    val t1 = System.nanoTime()
    val expected = bigList.distinct
    val t2 = System.nanoTime()
    val actual = ListUtil.distinctOnSorted[Int](bigList)
    val t3 = System.nanoTime()
    val actual2 = ListUtil.distinctOnSortedMut1(bigList)
    val t4 = System.nanoTime()
    val actual3 = ListUtil.distinctOnSortedMut2(bigList)
    val t5 = System.nanoTime()
    val actual4 = ListUtil.distinctOnSortedMut3(bigList)
    val t6 = System.nanoTime()
    val actual5 = ListUtil.distinctOnSortedMut4(bigList)
    val t7 = System.nanoTime()

    actual should be (expected)
    actual2 should be (expected)
    actual3 should be (expected)
    actual4 should be (expected)
    actual5 should be (expected)

    val distinctDur = t2 - t1
    val ourDur = t3 - t2

    ourDur should be < (distinctDur)

    print(s"distinct            : ${distinctDur / 1e6}ms\n")
    print(s"distinctOnSorted    : ${ourDur / 1e6}ms\n")
    print(s"distinctOnSortedMut1: ${(t4 - t3) / 1e6}ms\n")
    print(s"distinctOnSortedMut2: ${(t5 - t4) / 1e6}ms\n")
    print(s"distinctOnSortedMut3: ${(t6 - t5) / 1e6}ms\n")
    print(s"distinctOnSortedMut4: ${(t7 - t6) / 1e6}ms\n")
  }
}
def removeDuplicates[T](xs: List[T]): List[T] = xs match {
  case Nil => xs
  case head :: tail => head :: removeDuplicates(for (x <- tail if x != head) yield x)
}