2017-07-27 63 views
2

在我的應用程序中,我有很多地方,我需要獲取元組列表,groupBy通過元組的第一個元素並將其從其餘元素中刪除。例如,我有元組斯卡拉。如何創建接受不同元組的元組的一般方法?

(1, "Joe", "Account"), (1, "Tom", "Employer"), (2, "John", "Account"), and result should be Map(1 -> List(("Joe", "Account"), ("Joe", "Account")), 2 -> List(("John", "Account"))) 

很容易爲

data.groupBy(_._1).map { case (k, v) => k -> v.map(f => (f._2, f._3)) } 

但我期待通用的解決方案來實現的,因爲我可以有不同的arities,2,3,4,甚至7元組。 我覺得無形或Scalaz能幫助我,但我的經驗是這些庫中低,請指向一些示例

回答

6

這是很容易實現使用shapeless(爲簡單起見,我將不會被概括它所有的集合類型) 。有元組特定類型的類,它可以解構他們進入頭部和尾部叫IsComposite

import shapeless.ops.tuple.IsComposite 

def groupTail[P, H, T](tuples: List[P])(
    implicit ic: IsComposite.Aux[P, H, T]): Map[H, List[T]] = { 
    tuples 
     .groupBy(ic.head) 
     .map { case (k, vs) => (k, vs.map(ic.tail)) } 
} 

這適用於您的情況:

val data = 
    List((1, "Joe", "Account"), (1, "Tom", "Employer"), (2, "John", "Account")) 

assert { 
    groupTail(data) == Map(
    1 -> List(("Joe", "Account"), ("Tom", "Employer")), 
    2 -> List(("John", "Account")) 
) 
} 

以及針對不同類型的Tuple4

val data2 = List((1, 1, "a", 'a), (1, 2, "b", 'b), (2, 1, "a", 'b)) 

assert { 
    groupTail(data2) == Map(
    1 -> List((1, "a", 'a), (2, "b", 'b)), 
    2 -> List((1, "a", 'b)) 
) 
} 

可運行代碼可用at Scastie

+1

謝謝,奧列格。這是我想要的 –