我想知道获得给定序列的增加前缀的最优雅方法是什么。我的想法如下,但它不是纯粹的功能或任何优雅:
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)
答案 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)
}