【问题标题】:How can I pass a sum to the next iteration of a list using map, in Scala?在 Scala 中,如何使用 map 将总和传递给列表的下一次迭代?
【发布时间】:2017-05-29 04:48:33
【问题描述】:

我有以下课程:

class Task(val Time: Int)

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

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

因此,例如,如果 Task 列表的第一个元素的时间为 100,则生成的 TaskSchedule 列表的第一个元素的开始时间为 0,结束时间为 100。如果以下 Task 的时间为 200,则相应的taskSchedule 的开头为 100(前一个之和的结果),结尾为 300。

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

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

地图可以做到吗?还是我必须改变解决这个问题的方法?

【问题讨论】:

    标签: scala functional-programming iteration


    【解决方案1】:

    简单的解决方案

    TaskSchedule 的空列表和 0 的增量开始。在每一步,使用从 deltadelta + 时间创建一个 TaskSchedule。返回修改后的列表,其中包含我们添加当前时间的新 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
      }
    

    【讨论】:

      【解决方案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)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-01
        • 2016-05-26
        • 2011-09-15
        • 1970-01-01
        • 1970-01-01
        • 2021-07-08
        • 1970-01-01
        相关资源
        最近更新 更多