Scala - 增加序列的前缀

时间:2015-06-16 15:33:38

标签: scala

我想知道获得给定序列的增加前缀的最优雅方法是什么。我的想法如下,但它不是纯粹的功能或任何优雅:

val sequence = Seq(1,2,3,1,2,3,4,5,6)
var currentElement = sequence.head - 1
val increasingPrefix = sequence.takeWhile(e =>
            if (e > currentElement) {
                currentElement = e
                true
            } else
                false)

以上结果是:

List(1,2,3)

4 个答案:

答案 0 :(得分:6)

您可以使用@Samlik解决方案,并有效地压缩git log -p 0639706 变量,但在完成后将其映射出来。

currentElement

也适用于无限序列:

sequence.take(1) ++ sequence.zip(sequence.drop(1)).
    takeWhile({case (a, b) => a < b}).map({case (a, b) => b})

val sequence = Seq(1, 2, 3).toStream ++ Stream.from(1) 现在是无限sequence,但我们可以查看前10项:

Stream

现在,使用上面的代码段:

scala> sequence.take(10).toList
res: List[Int] = List(1, 2, 3, 1, 2, 3, 4, 5, 6, 7)

同样,val prefix = sequence.take(1) ++ sequence.zip(sequence.drop(1)). takeWhile({case (a, b) => a < b}).map({case (a, b) => b}) prefix,但不是无限。

Stream

N.b。:这不处理scala> prefix.toList res: List[Int] = List(1, 2, 3) 为空或前缀也是无限的情况。

答案 1 :(得分:3)

如果通过优雅,你的意思是简洁明了,那可能就像下面这样:

sequence.inits.dropWhile(xs => xs != xs.sorted).next

inits为我们提供了一个迭代器,它返回前缀最长的前缀。我们放弃所有未排序的并取下一个。

如果您不想进行所有排序,可以写下这样的内容:

sequence.scanLeft(Some(Int.MinValue): Option[Int]) {
  case (Some(last), i) if i > last => Some(i)
  case _ => None
}.tail.flatten

如果这项操作的表现非常重要(虽然可能不是),你会想要使用更为迫切的东西,因为这个解决方案仍会遍历整个集合(两次)。

答案 2 :(得分:3)

另一种皮肤猫的方法:

 val sequence = Seq(1,2,3,1,2,3,4,5,6)
 sequence.head :: sequence
                  .sliding(2)
                  .takeWhile{case List(a,b) => a <= b}
                  .map(_(1)).toList
// List[Int] = List(1, 2, 3)

答案 3 :(得分:0)

我会将优雅解释为最接近我们人类思考问题的方式的解决方案,尽管非常有效的算法也可以是一种优雅的形式。

val sequence = List(1,2,3,2,3,45,5)
val increasingPrefix = takeWhile(sequence, _ < _)

我相信此代码段捕获了我们大多数人可能会考虑解决此问题的方式。

这当然需要定义takeWhile

/**
 * Takes elements from a sequence by applying a predicate over two elements at a time.
 * @param xs The list to take elements from
 * @param f The predicate that operates over two elements at a time
 * @return This function is guaranteed to return a sequence with at least one element as
 *         the first element is assumed to satisfy the predicate as there is no previous
 *         element to provide the predicate with.
 */
def takeWhile[A](xs: Traversable[A], f: (Int, Int) => Boolean): Traversable[A] = {
  // function that operates over tuples and returns true when the predicate does not hold
  val not = f.tupled.andThen(!_)
  // Maybe one day our languages will be better than this... (dependant types anyone?)
  val twos = sequence.sliding(2).map{case List(one, two) => (one, two)}
  val indexOfBreak = twos.indexWhere(not)
  // Twos has one less element than xs, we need to compensate for that
  // An intuition is the fact that this function should always return the first element of
  // a non-empty list
  xs.take(i + 1)
}