Scala列表操作

Scala列表操作,scala,Scala,给定Int和Int类型的变量X的列表。在Scala功能性方法中,仅保留列表中的那些值(从列表的开头开始)以使列表值之和小于等于变量的最佳方法是什么。这非常接近于一行: def takeWhileLessThan(x: Int)(l: List[Int]): List[Int] = l.scan(0)(_ + _).tail.zip(l).takeWhile(_._1 <= x).map(_._2) 请注意,结果包括初始值,这就是我们在实现中采用尾部的原因 scala> List

给定Int和Int类型的变量X的列表。在Scala功能性方法中,仅保留列表中的那些值(从列表的开头开始)以使列表值之和小于等于变量的最佳方法是什么。

这非常接近于一行:

def takeWhileLessThan(x: Int)(l: List[Int]): List[Int] =
  l.scan(0)(_ + _).tail.zip(l).takeWhile(_._1 <= x).map(_._2)
请注意,结果包括初始值,这就是我们在实现中采用
尾部的原因

scala> List(1, 2, 3, 4).scan(0)(_ + _).tail
res1: List[Int] = List(1, 3, 6, 10)
现在我们将整个内容压缩到原始列表中。再次以我们的示例为例,如下所示:

scala> List(1, 2, 3, 4).scan(0)(_ + _).tail.zip(List(1, 2, 3, 4))
res2: List[(Int, Int)] = List((1,1), (3,2), (6,3), (10,4))
现在,我们可以使用
takeWhile
从该列表中获取尽可能多的值,直到累积总和大于目标值。假设在我们的示例中,我们的目标是5:

scala> res2.takeWhile(_._1 <= 5)
res3: List[(Int, Int)] = List((1,1), (3,2))

scala>res2.takeWhile(u.\u 1 res2.takeWhile(u.\u 1除了Travis的答案(并且为了完整性),您始终可以将这些类型的操作实现为
foldLeft

def takeWhileLessThanOrEqualTo(maxSum: Int)(list: Seq[Int]): Seq[Int] = {
  // Tuple3: the sum of elements so far; the accumulated list; have we went over x, or in other words are we finished yet
  val startingState = (0, Seq.empty[Int], false)
  val (_, accumulatedNumbers, _) = list.foldLeft(startingState) {
    case ((sum, accumulator, finished), nextNumber) =>
      if(!finished) {
        if (sum + nextNumber > maxSum) (sum, accumulator, true) // We are over the sum limit, finish
        else (sum + nextNumber, accumulator :+ nextNumber, false) // We are still under the limit, add it to the list and sum
      } else (sum, accumulator, finished) // We are in a finished state, just keep iterating over the list
  }
  accumulatedNumbers
}

这只会在列表上迭代一次,因此它应该更有效,但更复杂,需要阅读一些代码才能理解。

我将使用类似的方法,它更实用,应该更有效

def takeSumLessThan(x:Int,l:List[Int]): List[Int] = (x,l) match {
      case (_ , List())  => List()
      case (x, _) if x<= 0 => List()
      case (x, lh :: lt) => lh :: takeSumLessThan(x-lh,lt)
}

你尝试过什么吗?很酷的递归,虽然它不是尾部递归,如果输入列表很长,那么会导致堆栈溢出。
def takeWhileLessThanOrEqualTo(maxSum: Int)(list: Seq[Int]): Seq[Int] = {
  // Tuple3: the sum of elements so far; the accumulated list; have we went over x, or in other words are we finished yet
  val startingState = (0, Seq.empty[Int], false)
  val (_, accumulatedNumbers, _) = list.foldLeft(startingState) {
    case ((sum, accumulator, finished), nextNumber) =>
      if(!finished) {
        if (sum + nextNumber > maxSum) (sum, accumulator, true) // We are over the sum limit, finish
        else (sum + nextNumber, accumulator :+ nextNumber, false) // We are still under the limit, add it to the list and sum
      } else (sum, accumulator, finished) // We are in a finished state, just keep iterating over the list
  }
  accumulatedNumbers
}
def takeSumLessThan(x:Int,l:List[Int]): List[Int] = (x,l) match {
      case (_ , List())  => List()
      case (x, _) if x<= 0 => List()
      case (x, lh :: lt) => lh :: takeSumLessThan(x-lh,lt)
}
import scala.annotation.tailrec

implicit class MyList(l:List[Int]) {

    def takeSumLessThan(x:Int) = {
      @tailrec
      def f(x:Int,l:List[Int],acc:List[Int]) : List[Int] = (x,l) match {
        case (_,List()) => acc
        case (x, _ ) if x <= 0 => acc 
        case (x, lh :: lt ) =>  f(x-lh,lt,acc ++ List(lh))
      }
      f(x,l,Nil)
    }
  }
List(1,2,3,4,5,6,7,8).takeSumLessThan(10)