2016-01-15 33 views
5

Mam plik zawierający dane o komiwojażera, produktu, lokalizacja, SalesValuetworzenie i gromadzenie się mapa Mapa mapą ... w Scala

Na przykład:

Bob, Carrots, United States, 200 
Bill, Potatoes, England, 100 
Bob, Oranges, England, 50 
Bob, Carrots, United States, 20 

SalesValue może być zwięźle zgromadzone w hash hash hash w Perl za pomocą następującego kodu

while(<>){ 
    @cols = split(/,/); 
    $vals {$cols[0]} {$cols[1]} {$cols[2]} += $cols[3]; 
} 

Czy ktoś ma jakieś sugestie, jak to stworzenie mapy mapą mapie, plus akumulacja może być i najlepszy uzupełniony w scala?

Odpowiedz

6

Proponuję, aby połączyć te mapy jako operację monoid-append.

Najpierw musimy stworzyć mapy map mapach jako pojedynczych elementów:

val input = """Bob, Carrots, United States, 200 
       |Bill, Potatoes, England, 100 
       |Bob, Oranges, England, 50 
       |Bob, Carrots, United States, 20""".stripMargin.lines.toList 

val mmm = input.map(_.split(", ")) 
       .map { case Array(n, g, c, v) => Map(n -> Map(g -> Map(c -> v.toInt))) } 

mmm jest typu List[Map[String, Map[String, Map[String, Int]]]]:

List[Map[String, 
        Map[String, 
           Map[String, Int]]]] 

Wtedy moglibyśmy suml użyciu biblioteki jak scalaz lub cats:

import scalaz._, Scalaz._ 

println(mmm.suml) 

To będzie drukować (nie idented):

Map(Bill -> Map(Potatoes -> Map(England -> 100)), 
    Bob -> Map(Oranges -> Map(England -> 50), 
       Carrots -> Map(United States -> 220))) 

Aby pomóc zrozumieć, co dzieje się za działania .suml bym bezwstydnie sugerują do kasy tej prezentacji zrobiłem w ubiegłym roku https://speakerdeck.com/filippovitale/will-it-blend-scalasyd-february-2015


EDIT

Możemy również zobaczyć nasze mapy map map jako Foldable i używać foldMap do tego samego rezultatu:

kody
input.map(_.split(", ")) 
    .foldMap{ case Array(n, g, c, v) => Map(n -> Map(g -> Map(c -> v.toInt))) } 
+2

Innymi słowy, Perl jest tu zwycięzcą;) – Ashalynd

+0

... tak, ale czekam na Perl6 przed ponownym użyciem :-P Po tym trollu zaktualizuję odpowiedź bardziej szczegółowym wyjaśnieniem i alternatywną odpowiedzią. –

+0

Świetny sposób na przeczytanie mapy Map of Maps ... – BarneyW

0

Filippo Vitale są bardziej zwięzłe i elegancki

Jest to rozwiązanie bruteforce:

val t = 
    """Bob, Carrots, United States, 200 
    |Bill, Potatoes, England, 100 
    |Bob, Oranges, England, 50 
    |Bob, Carrots, United States, 20""".stripMargin 

def commaSplit(s: String) = s.splitAt(s.indexOf(",")) 

def f(arg: Seq[String]) = 
    arg 
    .groupBy(commaSplit(_)._1) 
    .map{ case (key, values) => key -> values.map(commaSplit(_)._2.drop(2))} 

val res = 
    f(t.split("\n")) 
    .map{ case (key, values) => key -> f(values).map { case (k, v) => 
     k -> f(v).map { case (country, amount) => country -> amount.map(_.toInt).sum } 
    }} 

że daje to wynik:

Map(Bob -> Map(Carrots -> Map(United States -> 220), 
       Oranges -> Map(England -> 50)), 
    Bill -> Map(Potatoes -> Map(England -> 100)))