List 如何在Scala中优雅地实现这个简单的算法

List 如何在Scala中优雅地实现这个简单的算法,list,scala,functional-programming,List,Scala,Functional Programming,我希望该方法的优雅实现具有以下(或类似)签名: def increasingSubsequences(xs: List[Int]): List[List[Int]] 它所做的是在不重新排序元素的情况下分割输入序列,以便结果中的每个子序列都严格递增 我自己实现了它,如下所示: def increasingSubsequences(list: List[Int], temp: List[Int] = Nil, res: List[List[Int]] = Nil): List[List[Int

我希望该方法的优雅实现具有以下(或类似)签名:

def increasingSubsequences(xs: List[Int]): List[List[Int]]
它所做的是在不重新排序元素的情况下分割输入序列,以便结果中的每个子序列都严格递增

我自己实现了它,如下所示:

  def increasingSubsequences(list: List[Int], temp: List[Int] = Nil, res: List[List[Int]] = Nil): List[List[Int]] = {
    (list, temp) match {
      case (x :: xs, t :: ts) if t < x => increasingSubsequences(xs, x :: temp, res)
      case (x :: xs, Nil) => increasingSubsequences(xs, List(x), res)
      case _ if list.nonEmpty => increasingSubsequences(list, Nil, temp.reverse :: res)
      case _ if temp.nonEmpty => (temp.reverse :: res).reverse
      case _ => res.reverse
    }
  }

我认为这符合你的要求。它确实使用了一个
if-else
子句,可以重构成另一个match语句,但我不喜欢它的样子。遗憾的是,如果不使用helper方法,我想不出一个好的方法来实现尾部递归

def increasingSubsequences(xs: List[Int]): List[List[Int]] = {
  xs match {
    case Nil => List(Nil) //in case someone calls on empty list
    case (head :: Nil) => List(head :: Nil) //base case
    case (head :: rest) => {
      val finishedRest = increasingSubsequences(rest)
      finishedRest match {
        case ((headOfFirst :: restOfFirst) :: restOfFinished) => {
          if (head < headOfFirst) (head :: headOfFirst :: restOfFirst) :: restOfFinished
          else List(List(head), headOfFirst::restOfFirst) ++ restOfFinished
        }
      }
    }
  }
}
def递增子序列(xs:List[Int]):List[List[Int]={
xs匹配{
case Nil=>List(Nil)//如果有人调用空列表
案例(head::Nil)=>List(head::Nil)//基本案例
案例(头部::休息)=>{
val finishedRest=递增子序列(剩余)
最后一场比赛{
案例((HeadOfffirst::RestOfffirst)::RestOffFinished)=>{
如果(head
与您指定的有两个小差异:

  • List()
    生成
    List(List())
  • List(1,2,3,4,5)
    生成
    List(List(1,2,3,4,5)
我只能假设您打算以这种方式指定它们,否则,它们不适合
List[List[Int]]
的返回类型*


*我还应该提到,第一个是可以的,因为Scala不介意内部
List[Int]
被暗示,而且它实际上会产生这样的结果,如果您将第一个案例更改为简单的
Nil=>Nil
,我使用List的
foldLeft
完成了这项工作:

def increasingSubsequences(list:List[Int]) =
  list.foldLeft(List[List[Int]]())((accum, value) => {
    accum match {
      case Nil => List(List(value))
      case headList :: tailList => {
        headList match {
          case head :: tail if value > head => List(headList :+ value) ++ tailList
          case _ => List(List(value)) ++ accum
        }
      }
    }
}).reverse
正如@Dimitri所指出的,如果使用
映射(.\u反向)
,复杂性可能会更好。所以,你可以决定:)


您可以首先找到所有拆分点,然后拆分它们。

反转列表,然后使用
折叠ft

def increasingSubsequences(list: List[Int]) = list.reverse.foldLeft(List[List[Int]]()) {
  case (a :: as, b) if b < a.head => (b :: a) :: as   // same subsequence
  case (as, b)                    => List(b)  :: as   // new subsequence
}
def递增子序列(list:list[Int])=list.reverse.foldLeft(list[list[Int]])){
如果b(b::a)::as//相同的子序列
case(as,b)=>List(b)::as//新的子序列
}
使用,它相当简单:

import scalaz.std.list._

def increasingSubsequences(xs: List[Int]) = groupWhen(xs)(_ < _)
导入scalaz.std.list_
def递增子序列(xs:List[Int])=groupWhen(xs)(\u<\ u

我不确定,但就复杂性而言,我认为
列表(value::headList)
然后
.map(\uu.reverse)
在最终结果上会稍微好一些。谢谢你,这段精彩的代码。请接受我的编辑建议(您的原始代码返回List(List()),而不是Nil作为Nil输入。感谢您的回答,它非常有用。我给了您+1,但是,我接受了@LRLucena的回答,因为他只使用核心库。
  def increasingSubsequences(xs: List[Int]): List[List[Int]] = {
    val splits = xs.sliding(2).zipWithIndex.toList
      .map { case (sub, i) => if (sub(0) >= sub(1)) i + 1 else -1 } filter (_ > 0)
    (List(0, splits.head) :: splits.sliding(2).toList ++ List(List(splits.last, xs.size)))
      .map { case pos => xs.slice(pos(0), pos(1)) }
  }
def increasingSubsequences(list: List[Int]) = list.reverse.foldLeft(List[List[Int]]()) {
  case (a :: as, b) if b < a.head => (b :: a) :: as   // same subsequence
  case (as, b)                    => List(b)  :: as   // new subsequence
}
import scalaz.std.list._

def increasingSubsequences(xs: List[Int]) = groupWhen(xs)(_ < _)