2011-02-15 11 views
7

muszę bardziej zwięzły sposób przekształcić sekwencję krotek na mapie map map ... jako podpis uzyskać w przypadku Tuple4:4-Tuple Sequence Aby Mapa Mapy Mapy

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

Poniższy kod pokazuje mój ostatni kod brzydki, ja stucked z (typu A do D arbitralnej):

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

Uwaga wykorzystanie head w val z.

Byłoby miło mieć bardziej zwięzły sposób na tylko Tuple4, ale ponadto ciekawe, jak uogólnić to na TupleN (N> = 2).

Czy jest tam dobre podejście do czyjegoś umysłu?

Dziękujemy!

Odpowiedz

8

Najlepszym mogę wymyślić jest

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

uogólniając do krotek wyższych liczbę operandów jest dość straightfoward ... wystarczy dodać dodatkowe aplikacje zagnieżdżone wartości mapValues ​​(_groupBy (_._ n). ... i odpowiednio dopasuj ostateczne dopasowanie do wzorca

Pełne uogólnienie tego jako funkcji przez krotki arbitralnego ar była możliwa przy użyciu HLists, ale to najprawdopodobniej byłoby o wiele bardziej ciężkim rozwiązaniem, niż jest to potrzebne tutaj. Opuszczę tę linię ataku jako ćwiczenie dla pytającego (lub innych komentujących ;-).

+0

Bardzo ładne rozwiązanie! Dziękuję Ci! –

+0

Jako uzupełnienie: Należy mieć świadomość, że 'mapValues' zwraca widok. Zobacz fajną odpowiedź Rex Kerr tutaj: http://stackoverflow.com/questions/5433578/subsetof-versus-forall-contains –

1

Sugeruję implicits na krotki:

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