如何在Scala中使用map将一个总和传递给列表的下一次迭代?

时间:2017-05-28 20:05:31

标签: scala functional-programming iteration

我有以下课程:

class Task(val Time: Int)

class TaskSchedule(val Start: Int, val: End: Int)

我的目标是创建一个TaskSchedule列表,它从任务列表中迭代地总计时间。

因此,例如,如果任务列表的第一个元素的时间为100,则生成的TaskSchedule列表的第一个元素将具有开始0和结束100.如果以下任务的时间为200,则相应的taskSchedule的起点为100(前一个的总和的结果)和300的结尾。

我试图用地图做这个,但我不知道如何获得前一个总和,或者如何将总和传递给下一个迭代。

tasks.map(t => {
    new TaskSchedule(
    //need previous sum or 0 if first,
    )
})

地图可以吗?或者我是否必须改变我对此问题的处理方法?

2 个答案:

答案 0 :(得分:2)

简单解决方案

TaskSchedule的空列表开始,增量为0.在每一步,使用从TaskScheduledelta +时间创建delta。将修改后的列表与我们添加了当前时间的新delta一起返回,以便下一步说明它。

一些附注,类别参数在Scala中不需要大写,你可以在那里使用case class

  case class Task(time: Int)

  case class TaskSchedule(start: Int, end: Int)

  def interleave(tasks: List[Task]): List[TaskSchedule] = {
    val (schedules, _) = tasks.foldLeft(List.empty[TaskSchedule] -> 0) { case ((list, delta), task) =>
      (TaskSchedule(delta, delta + task.time) :: list) -> (delta + task.time)
    }
    schedules.reverse
  }

   val result = interleave(List(Task(100), Task(200)))

   Console.println(result)
   // List(TaskSchedule(0,100), TaskSchedule(100,300))

为避免逆转,您可以改用append。

  def interleave(tasks: List[Task]): List[TaskSchedule] = {
    val (schedules, _) = tasks.foldLeft(List.empty[TaskSchedule] -> 0) { case ((list, delta), task) =>
          (list :+ TaskSchedule(delta, delta + task.time)) -> (delta + task.time)
    }
    schedules
  }

答案 1 :(得分:2)

Seq#scanLeft(...)操作最接近您的需要:

tasks.
  scanLeft(new TaskSchedule(0, 0)) {
    case (lastSched: TaskSchedule, task: Task) => new TaskSchedule(lastSched.End, lastSched.End + task.Time)
  }.
  tail

这是一个替代实现,您无需先创建new TaskSchedule(0, 0)

tasks.tail.scanLeft(new TaskSchedule(0, tasks.head.Time)) {
  case (lastSched: TaskSchedule, task: Task) => new TaskSchedule(lastSched.End, lastSched.End + task.Time)
}

我会让你自己决定哪个更干净(我很难决定自己,虽然第二个实现创建了一个更少的对象)。

如果您制作TaskTaskSchedule案例类,可以让事情变得更清晰:

case class Task(time: Int)
case class TaskSchedule(start: Int, end: Int)

tasks: Seq[Task] = ...
tasks.tail.scanLeft(TaskSchedule(0, tasks.head.time)) {
  case (TaskSchedule(_, lastEnd), Task(time)) => TaskSchedule(lastEnd, lastEnd + time)
}

顺便提一下,Scala约定是用小写命名变量(即time而不是Timestart而不是Startend代替End)。