2011-02-15 20 views
7

necesito una manera más concisa para transformar una secuencia de tuplas en un mapa de mapas de mapas ... Como una firma que se interponen en caso de Tuple4:4-tupla secuencia Para Mapa de Mapas Mapas de

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

el siguiente código muestra mi reciente código fea, me stucked con (tipo A-D arbitraria):

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 el uso de head en val z.

Sería bueno tener una forma más concisa para solo Tuple4, pero además es interesante como generalizar esto a TupleN (N> = 2).

¿Hay algún enfoque agradable en la mente de alguien por ahí?

¡Gracias!

Respuesta

8

Lo mejor que puedo ocurre es,

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

Generalizando a tuplas de mayor aridad es bastante straightfoward ... sólo tiene que añadir aplicaciones anidadas adicionales de mapValues ​​(_groupBy (_._ n). ... y ajuste la concordancia del patrón final en consecuencia.

Generalizando completamente esto como una función sobre tuplas de ar arbitrarias Sería posible usar HLists, pero probablemente sería una solución mucho más pesada de lo que se necesita aquí. Dejaré esta línea de ataque como ejercicio para el que pregunta (u otros comentaristas ;-).

+0

Muy buena solución! ¡Gracias! –

+0

Como complemento: se debe tener en cuenta que 'mapValues' devuelve una vista. Vea la buena respuesta de Rex Kerr aquí: http://stackoverflow.com/questions/5433578/subsetof-versus-forall-contains –

1

me gustaría sugerir implícitos en las tuplas:

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