Scala:按持续时间总和排序列表

时间:2017-06-15 21:55:53

标签: scala sorting functional-programming

我有以下课程:

Task(id: String, time: Duration)

Product(id: String, tasks: List[Task])

然后,我有一个列表list: List[Product],其中包含以下元素:

("P1", List(Task("T1", 15 minute), Task("T2", 10 minute)))

("P2", List(Task("T3", 10 minute)))

("P3", List(Task("T1", 15 minute)))

现在我想按每个产品生产所需的时间总和来订购列表。在这种情况下,我希望输出如此:

("P2", List(Task("T3", 10 minute))) // 10 min total

("P3", List(Task("T1", 15 minute))) // 15 min total

("P1", List(Task("T1", 15 minute), Task("T2", 10 minute))) // 25 min total

我想过做这样的事情,但它不起作用:

list.sortBy(p => p.tasks.map(t => t.time))

你们知道我怎么能这样做?

3 个答案:

答案 0 :(得分:2)

你非常接近(你没有在内部列表中总结持续时间):

list.sortBy(p => p.tasks.foldLeft(Duration.ZERO)(_ plus _.time))

请注意,在此处编写单独的函数可能更有意义:

def totalTime(tasks: Seq[Task]): Duration 
  = tasks.foldLeft(Duration.ZERO)(_ plus _.time) 

因为那时你可以写:

list.sortBy(p => totalTime(p.tasks))

备注:

你也可以使用reduce,虽然你应该安全地使用(即不要假设你的列表是非空的)

def totalTime(tasks: Seq[Task]) 
  = tasks.map(_.time).reduceLeftOption(_ plus _).getOrElse(Duration.ZERO)

更高级

如果您确定内部列表不能为空,则应使用强制执行此操作的数据类型,例如 scalaz NonEmptyList。然后你可以使用:

def totalTime(tasks: NonEmptyList[Task])
  = tasks.map(_.time).foldl1(_ plus _)

事实上,你可以利用scalaz(foldMap)中的内置 map-reduce ,虽然这需要声明Semigroup[Duration]

implicit val DurationSemigroup: Semigroup[Duration]
  = Semigroup.instance(_ plus _)

def totalTime(tasks: NonEmptyList[Task]) = tasks.foldMap1(_.time))

答案 1 :(得分:1)

按时间将时间转换为纳米

scala> list.sortBy(p => p.tasks.map(_.time.toNanos).sum)
result: List[Product] = List(Product(P1,List(Task(T1,15 minutes), Task(T2,10 minutes))))

答案 2 :(得分:1)

以下是对列表进行排序的一种方法:

list.sortBy(
  p => p.tasks.map( t => t.time.toMillis ).sum
)
res1: List[Product] = List(
  Product(P2,List(Task(T3,10 minutes))),
  Product(P3,List(Task(T1,15 minutes))),
  Product(P1,List(Task(T1,15 minutes), Task(T2,10 minutes)))
)

验证排序列表:

list.map(
  p => ( p.id, p.tasks.map( t => t.time.toMinutes ).sum )
)
res2: List[(String, Long)] = List((P1,25), (P2,10), (P3,15)