我确信有一种优雅/有趣的方式, 但我只能想到一个或多或少复杂的递归解决方案。
改述: 是否有任何标准的lib(集合)方法,也没有简单的组合来获取列表的第一个不同的元素?
scala> val s = Seq(3, 5, 4, 1, 5, 7, 1, 2)
s: Seq[Int] = List(3, 5, 4, 1, 5, 7, 1, 2)
scala> s.takeWhileDistinct //Would return Seq(3,5,4,1), it should preserve the original order and ignore posterior occurrences of distinct values like 7 and 2.
答案 0 :(得分:7)
如果你想要快速,那么
{ val hs = scala.collection.mutable.HashSet[Int]()
s.takeWhile{ hs.add } }
会做到这一点。 (额外的大括号可防止泄漏临时值hs
。)
答案 1 :(得分:2)
这是一种最短的方法,最多为O(2logN)
。
implicit class ListOps[T](val s: Seq[T]) {
def takeWhileDistinct: Seq[T] = {
s.indexWhere(x => { s.count(x==) > 1 }) match {
case ind if (ind > 0) => s.take(
s.indexWhere(x => { s.count(x==) > 1 }, ind + 1) + ind).distinct
case _ => s
}
}
}
val ex = Seq(3, 5, 4, 5, 7, 1)
val ex2 = Seq(3, 5, 4, 1, 5, 7, 1, 5)
println(ex.takeWhileDistinct.mkString(", ")) // 3, 4, 5
println(ex2.takeWhileDistinct.mkString(", ")) // 3, 4, 5, 1
查看here了解实时结果。
答案 2 :(得分:1)
有趣的问题。这是另一种选择。首先,让我们获取s
的流,这样我们就可以避免不必要的工作(尽管开销很可能比保存的工作更大,但遗憾的是)。
val s = Seq(3, 5, 4, 5, 7, 1)
val ss = s.toStream
现在我们可以再次建立s,但是跟踪是否有重复,并在第一个停止:
val newS = ss.scanLeft(Seq[Int]() -> false) {
case ((seen, stop), current) =>
if (stop || (seen contains current)) (seen, true)
else ((seen :+ current, false))
}
现在剩下的就是拿下最后一个元素而不重复,然后放下标志:
val noRepetitionsS = newS.takeWhile(!_._2).last._1
答案 3 :(得分:0)
问题比我正在寻找的std lib函数更简单(takeWhileConditionOverListOfAllAlreadyTraversedItems):
scala> val s = Seq(3, 5, 4, 1, 5, 7, 1, 2)
scala> s.zip(s.distinct).takeWhile{case(a,b)=>a==b}.map(_._1)
res20: Seq[Int] = List(3, 5, 4, 1)
答案 4 :(得分:0)
雷克斯的一个变种(虽然我更喜欢他......)
这一个功能始终正常,使用了很少见的scanLeft
方法。
val prevs = xs.scanLeft(Set.empty[Int])(_ + _)
(xs zip prevs) takeWhile { case (x,prev) => !prev(x) } map {_._1}
更新
一个懒惰版本(使用迭代器,用于提高效率):
val prevs = xs.iterator.scanLeft(Set.empty[Int])(_ + _)
(prevs zip xs.iterator) takeWhile { case (prev,x) => !prev(x) } map {_._2}
如果需要,可以将生成的迭代器转回序列,但是这对输入和输出上的迭代器也很有效。