我有以下课程:
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))
你们知道我怎么能这样做?
答案 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)