2011-02-15 10 views
7

ho bisogno di un modo più conciso per trasformare una sequenza di tuple in una mappa di mappe di mappe ... Come una firma ottengo in caso di Tuple4:4 parametri Sequenza alla mappa di Mappe di Mappe

def tuple4Seq2MapOfMaps[A,B,C,D](seq: Seq[(A,B,C,D)]): Map[A,Map[B,Map[C,D]]] 

il codice seguente mostra il mio recente codice brutto, ho stucked con (tipo A-D arbitrario):

type A = Int 
type B = Double 
type C = String 
type D = Boolean 
val tupleSeq = Seq[(A,B,C,D)](
    (1,1.0D,"a",true), 
    (1,1.0D,"b",true), 
    (1,1.0D,"c",false) 
) 
val x = tupleSeq.groupBy{ _._1 }.map{ case (k,s) => (k,s.map{ x => (x._2,x._3,x._4) }) } 
val y = x.map{ case (k,s) => (k,s.groupBy{_._1}.map{ case (k,s) => (k,s.map{ x => (x._2,x._3) }) }) } 
val z = y.map{ case (k1,m) => (k1,m.map{ case (k2,s1) => (k2,s1.groupBy{_._1}.map{ case (k3,s2) => (k3,s2.map{ _._2 }.head) }) }) } 

val m = z(1)(1.0D) 
println(m("b")) 

Nota l'uso di head a val z.

Sarebbe bello avere un modo più conciso solo per Tuple4, ma inoltre interessante come generalizzare questo a TupleN (N> = 2).

C'è un buon approccio nella mente di qualcuno là fuori?

Grazie!

risposta

8

Il meglio che posso venire in mente è,

tupleSeq.groupBy(_._1). 
    mapValues(_.groupBy(_._2). 
    mapValues(_.groupBy(_._3). 
     mapValues{ case Seq(p) => p._4 })) 

Generalizzando di tuple di alto arietà è abbastanza straightfoward ... basta aggiungere ulteriori applicazioni nidificati di mapValues ​​(_groupBy (_._ n). ... e regolare il pattern match finale conseguenza.

completamente generalizzare questo come una funzione in tuple di ar arbitraria Sarebbe possibile utilizzare le liste HL, ma questa sarebbe molto probabilmente una soluzione molto più pesante di quella necessaria qui. Lascerò questa linea di attacco come esercizio per l'interrogante (o altri commentatori ;-).

+0

Soluzione molto bella! Grazie! –

+0

Come supplemento: Si dovrebbe essere consapevoli del fatto che 'mapValues' restituisce una vista. Vedi la bella risposta di Rex Kerr qui: http://stackoverflow.com/questions/5433578/subsetof-versus-forall-contains –

1

Io suggerirei impliciti sulle tuple:

implicit def Tup3Cut[A,B,C](tup: (A,B,C)) = new { 
    def decapitate = (tup._2,tup._3) 
} 
implicit def Tup4Cut[A,B,C,D](tup: (A,B,C,D)) = new { 
    def decapitate = (tup._2,tup._3,tup._4) 
} 

val tupleSeq = Seq((1,1d,"a",true),(1,1d,"b",true),(1,1d,"c",false),(1,2d,"c",true)) 

tupleSeq.groupBy(_._1).mapValues(
    _.map(_.decapitate).groupBy(_._1).mapValues(_.map(_.decapitate).toMap) 
)