2016-01-15 17 views
5

Ich habe eine Datei auf Verkäufer, die Daten, Produkt, Ort, SalesValueErstellen und eine Karte von Karte von Karte Akkumulieren ... in scala

Zum Beispiel:

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

Die SalesValue kann kurz und bündig sein akkumuliert in eine Hash-Hash-Hash in perl den folgenden Code

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

Hat jemand irgendwelche Vorschläge, wie diese Schaffung einer Karte Karte Karte, sowie die Akkumulation, könnte mich mit am besten in Scala umgesetzt?

Antwort

6

Ich würde vorschlagen, die Zusammenführung dieser Karten als monoid-append Operation zu sehen.

Zuerst erstellen wir die Karten für Karten von Karten als Einzelelemente:

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 vom Typ List[Map[String, Map[String, Map[String, Int]]]]:

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

Dann könnten wir suml eine Bibliothek wie scalaz oder cats mit:

import scalaz._, Scalaz._ 

println(mmm.suml) 

Dies druckt (nicht eingerückt):

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

Um zu helfen zu verstehen, was sich hinter dem .suml Betrieb geschieht Ich würde schamlos diese Präsentation schlage ich im letzten Jahr https://speakerdeck.com/filippovitale/will-it-blend-scalasyd-february-2015


bearbeitet zur Kasse

Wir können auch unsere Karten von Karten von Karten als Foldable sehen und verwenden foldMap für das gleiche Ergebnis:

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

Mit anderen Worten, Perl ist der Gewinner hier;) – Ashalynd

+0

... ja, aber ich warte auf Perl6 bevor ich es wieder benutze :-P Nach diesem Troll werde ich die Antwort mit einer ausführlicheren Erklärung und einer alternativen Antwort aktualisieren. –

+0

Tolle Möglichkeit, in eine Karte der Karte von Karten zu lesen ... – BarneyW

0

Filippo Vitale Codes sind prägnant und elegant

Dies ist eine Brute-Force-Lösung:

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

, dass dieses Ergebnis gibt:

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