Scala 按部分减少顺序

Scala 按部分减少顺序,scala,collections,Scala,Collections,我有一个序列Seq[T],我想做部分reduce。例如,对于一个Seq[Int]我想得到由单调区域的最长部分和组成的Seq[Int]。例如: val s = Seq(1, 2, 4, 3, 2, -1, 0, 6, 8) groupMonotionic(s) = Seq(1 + 2 + 4, 3 + 2 + (-1), 0 + 6 + 8) 我在寻找一些方法,比如带有签名的条件折叠(z:B)((B,T)=>B,(T,T)=>Boolean),其中谓词声明终止当前总和聚合的位置,但在Seq的子序

我有一个序列
Seq[T]
,我想做部分reduce。例如,对于一个
Seq[Int]
我想得到由单调区域的最长部分和组成的
Seq[Int]
。例如:

val s = Seq(1, 2, 4, 3, 2, -1, 0, 6, 8)
groupMonotionic(s) = Seq(1 + 2 + 4, 3 + 2 + (-1), 0 + 6 + 8)
我在寻找一些方法,比如带有签名的条件折叠(z:B)((B,T)=>B,(T,T)=>Boolean),其中谓词声明终止当前总和聚合的位置,但在
Seq的子序列层次结构中似乎没有类似的东西


使用Scala Collection API而不使用可变变量的解决方案是什么?

这里有一种方法可以做到这一点(使用Scala 2.13
):

List.unfold
只要unfoling函数提供
一些
就可以迭代。它从一个初始状态开始,即要展开的项目列表。在每次迭代中,我们根据标题“两个元素的差异”的符号来确定状态(要展开的剩余元素)。展开的元素是共享相同单调性的标题项,展开状态成为其他剩余元素

List#span
将列表拆分为元组,元组的第一部分包含与应用的谓词匹配的元素,直到谓词停止有效。元组的第二部分包含其余元素。它完全符合
列表的预期返回类型。展开
的展开功能,即
选项[(A,s)]
(在本例中为
选项[(列表[Int],列表[Int])]

Int.signum
返回
-1
0
1
,具体取决于应用它的整数的符号

请注意,必须将第一项放回结果中,因为它没有确定其符号的祖先(
match{case head::rest=>(first::head)::rest}


要应用缩减函数(在本例中为求和),我们可以映射最终结果:
.map(u.sum)

这里有一种方法,使用
foldLeft
使用Tuple3累加器遍历数值列表
(ListofList,prevElem,prevTrend)
存储
上一个元素
上一个趋势
以有条件地在当前迭代中组合列表列表:

val list = List(1, 2, 4, 3, 2, -1, 0, 6, 8)

val isUpward = (a: Int, b: Int) => a < b

val initTrend = isUpward(list.head, list.tail.head)

val monotonicLists = list.foldLeft( (List[List[Int]](), list.head, initTrend) ){
  case ((lol, prev, prevTrend), curr) =>
    val currTrend = isUpward(curr, prev)
    if (currTrend == prevTrend)
      ((curr :: lol.head) :: lol.tail , curr, currTrend)
    else
      (List(curr) :: lol , curr, currTrend)
}._1.reverse.map(_.reverse)
// monotonicLists: List[List[Int]] = List(List(1, 2, 4), List(3, 2, -1), List(0, 6, 8))

在Scala 2.13+中与猫一起工作

import scala.util.chaining._
import cats.data._
import cats.implicits._

val s = List(1, 2, 4, 3, 2, -1, 0, 6, 8)

def isLocalExtrema(a: List[Int]) =
    a.max == a(1) || a.min == a(1)

implicit class ListOps[T](ls: List[T]) {
  def multiSpanUntil(f: T => Boolean): List[List[T]] = ls.span(f) match {
    case (h, Nil) => List(h)
    case (h, t) => (h ::: t.take(1)) :: t.tail.multiSpanUntil(f)
  }
}

def groupMonotionic(groups: List[Int]) = groups match {
  case Nil => Nil
  case x  if x.length < 3 => List(groups.sum)      
  case _ =>

    groups
      .sliding(3).toList
      .map(isLocalExtrema)
      .pipe(false :: _ ::: List(false))
      .zip(groups)
      .multiSpanUntil(!_._1)
      .pipe(Nested.apply)
      .map(_._2)
      .value
      .map(_.sum)

}

println(groupMonotionic(s))
//List(7, 4, 14)
导入scala.util.chaining_
导入cats.data_
进口猫_
val s=列表(1,2,4,3,2,-1,0,6,8)
def isLocalExtrema(a:List[Int])=
a、 max==a(1)| a.min==a(1)
隐式类ListOps[T](ls:List[T]){
def multispan(f:T=>Boolean):List[List[T]=ls.span(f)匹配{
案例(h,Nil)=>列表(h)
case(h,t)=>(h::t.take(1))::t.tail.multispan(f)
}
}
def groupMonotionic(组:列表[Int])=组匹配{
案例Nil=>Nil
如果x.length<3=>列表(groups.sum),则为案例x
案例=>
组
.滑动式(3)收费表
.map(isLocalExtrema)
.pipe(false::::列表(false))
.zip(组)
.多平移(!\uu.\u 1)
.pipe(嵌套的.apply)
.map(u.u 2)
价值
.map(u.sum)
}
println(集团单一)
//名单(7、4、14)
monotonicLists.map(_.sum)
// res1: List[Int] = List(7, 4, 14)
import scala.util.chaining._
import cats.data._
import cats.implicits._

val s = List(1, 2, 4, 3, 2, -1, 0, 6, 8)

def isLocalExtrema(a: List[Int]) =
    a.max == a(1) || a.min == a(1)

implicit class ListOps[T](ls: List[T]) {
  def multiSpanUntil(f: T => Boolean): List[List[T]] = ls.span(f) match {
    case (h, Nil) => List(h)
    case (h, t) => (h ::: t.take(1)) :: t.tail.multiSpanUntil(f)
  }
}

def groupMonotionic(groups: List[Int]) = groups match {
  case Nil => Nil
  case x  if x.length < 3 => List(groups.sum)      
  case _ =>

    groups
      .sliding(3).toList
      .map(isLocalExtrema)
      .pipe(false :: _ ::: List(false))
      .zip(groups)
      .multiSpanUntil(!_._1)
      .pipe(Nested.apply)
      .map(_._2)
      .value
      .map(_.sum)

}

println(groupMonotionic(s))
//List(7, 4, 14)