2012-08-28 6 views
8

Angenommen, SieCount Vorkommen jedes Element in einer Liste [Liste [T]] in Scala

val docs = List(List("one", "two"), List("two", "three")) 

wo zum Beispiel haben List („eins“, „zwei“) stellt ein Dokument Begriffe „einen“ und „zwei“ enthält, und Sie mögen für jeden Begriff eine Karte mit der Dokumenthäufigkeit bauen, das heißt in diesem Fall

Map("one" -> 1, "two" -> 2, "three" -> 1) 

Wie Würdest du das in Scala machen? (Und auf effiziente Art und Weise, unter der Annahme, eine viel größere Datenmenge.)

Meine erste Java-like Gedanke ist eine veränderbare Karte zu verwenden:

val freqs = mutable.Map.empty[String,Int] 
for (doc <- docs) 
    for (term <- doc) 
    freqs(term) = freqs.getOrElse(term, 0) + 1 

, die gut genug funktioniert, aber ich frage mich, wie Sie könnte Machen Sie das "funktional", ohne auf eine veränderbare Karte zurückzugreifen?

Antwort

12
docs.flatten.foldLeft(new Map.WithDefault(Map[String,Int](),Function.const(0))){ 
    (m,x) => m + (x -> (1 + m(x)))} 

Was für ein Zugwrack!

[Bearbeiten]

Ah, das ist besser!

docs.flatten.foldLeft(Map[String,Int]() withDefaultValue 0){ 
    (m,x) => m + (x -> (1 + m(x)))} 
+2

Sie können die Map-Initialisierung verkürzen:' docs.flatten.foldLeft (Map [String, Int]() withDefaultValue 0) {(m, x) => ...} ' – paradigmatic

+0

Danke!Ich habe keine Ahnung, warum ich diese Funktion übersehen habe ... – Landei

+1

Es scheint schneller als 'groupBy', also dies als akzeptiert zu markieren. Aber beide Antworten sind interessant. –

18

Versuchen Sie folgendes:

scala> docs.flatten.groupBy(identity).mapValues(_.size) 
res0: Map[String,Int] = Map(one -> 1, two -> 2, three -> 1) 

Wenn Sie die zählt oft zu gehen, den Zugriff, dann sollte man mapValues vermeiden, da sie „faul“ ist, und somit würde die Größe bei jedem Zugriff neu berechnen. Diese Version gibt Ihnen das gleiche Ergebnis, aber nicht die Neuberechnungen erfordern:

docs.flatten.groupBy(identity).map(x => (x._1, x._2.size)) 

Die identity Funktion bedeutet nur x => x.

+0

Schön. Es scheint langsamer als mit einer veränderlichen Karte mit nur ~ 10k Bedingungen. Kosten für die Umwandlung von Sammlungen 3 mal? –

+0

Ja, es ist schön und funktional, aber das Kopieren all dieser Daten trägt nicht zur Effizienz bei. Die veränderbare Map-Version verschwendet nicht viel Zeit. – dhg

+0

+1 für mich zu lehren, dass 'mapValues' die Karte bei jedem Durchlauf neu berechnet. Aber in diesem Fall sollte ein Ausdruck mit "foldLeft" besser sein als "groubBy". – paradigmatic

Verwandte Themen