2017-06-15 71 views
1

我有以下類別:斯卡拉:由長的總和排序列表

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)) 

難道你們知道我怎麼能做到這一點?

回答

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) 
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

您是非常接近(你是不是總結在內部列表中的持續時間):

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) 

更先進的

如果你確信你的內心列表不能爲空,您應該使用哪種強制實施此數據類型,如scalazNonEmptyList。然後,您可以使用:

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

事實上,你可以利用內置的地圖降低scalazfoldMap),儘管這將需要聲明一個Semigroup[Duration]

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

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