2017-11-29 1 views
2

Ich bin ziemlich neu in Scala, so hoffentlich tolerieren Sie diese Frage in dem Fall, dass Sie es noobish finden :)Kann ich die Map-Sammlung in Scala mit For-Yield-Syntax zurückgeben?

ich eine Funktion geschrieben, die eine Seq von Elementen Ausbeute Syntax gibt:

def calculateSomeMetrics(names: Seq[String]): Seq[Long] = { 
    for (name <- names) yield { 
    // some auxiliary actions 
    val metrics = somehowCalculateMetrics() 
    metrics 
    } 
} 

jetzt muss ich es ändern, um eine Karte zurück die ursprünglichen Namen gegen jeden der berechneten Werte zu erhalten:

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = { ... } 

ich versucht habe die gleiche Ausbeute-Syntax zu verwenden, aber ein Tupel statt eines einzelnen Elements zu erhalten :

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = { 
    for (name <- names) yield { 
    // Everything is the same as before 
    (name, metrics) 
    } 
} 

jedoch der Compiler interpretiert es Seq[(String, Long)], gemäß der Compiler-Fehlermeldung

type mismatch; 
    found : Seq[(String, Long)] 
    required: Map[String, Long] 

Also ich frage mich, was ist die "kanonische Scala Art und Weise", so etwas zu implementieren?

+2

Ähnliche: https://StackOverflow.com/Questions/40525115/How-to-choose-the-output-Collection-type-in-seq-map –

Antwort

5

Entweder:

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = { 
    (for (name <- names) yield { 
    // Everything is the same as before 
    (name, metrics) 
    }).toMap 
} 

Oder:

names.map { name => 
    // doStuff 
    (name, metrics) 
}.toMap 
+0

Vielen Dank! Sind diese technisch gleichwertig? –

+1

@VasiliyGalkin Ja, das sind sie. Ersteres wird in letzterem kompiliert. –

+1

Großartig! Danke noch einmal! –

8

Die effiziente Art und Weise unterschiedliche Sammlungstypen schaffen scala.collection.breakOut verwendet. Es arbeitet mit Map s und für Comprehensions zu:

import scala.collection.breakOut 

val x: Map[String, Int] = (for (i <- 1 to 10) yield i.toString -> i)(breakOut) 

x: Map [String, Int] = Karte (8 -> 8, 4 -> 4, 9 -> 9, 5 -> 5, 10 -> 10, 6 -> 6, 1 -> 1, 2 -> 2, 7 -> 7, 3 -> 3)

In Ihrem Fall sollte es funktioniert auch:

import scala.collection.breakOut 

def calculateSomeMetrics(names: Seq[String]): Map[String, Long] = { 
    (for (name <- names) yield { 
    // Everything is the same as before 
    (name, metrics) 
    })(breakOut) 
} 

Vergleich mit toMap Lösungen: vor toMap erstellt ein Zwischenprodukt Seq von Tuple2 s (die übrigens vielleicht eine Map auch in bestimmten Fällen) und dass es die Map erzeugt, während breakOut diese Zwischen Seq Schöpfung läßt und schafft die Map direkt anstelle der Zwischen Seq.

Normalerweise ist dies kein großer Unterschied in der Speicher- oder CPU-Auslastung (+ GC-Druck), aber manchmal sind diese Dinge wichtig.

+2

Ich würde weg von der Verwendung von 'breakOut' gehen, bis dieser spezifische Code ein Engpass wird. Es ist kontraintuitiv zu lesen und zu verstehen. –

+0

@YuvalItzchakov Ich stimme zu, deshalb habe ich den letzten Satz hinzugefügt. –

+0

In meinem Fall ist die Verstärkung nicht groß genug im Vergleich zu den möglichen "WTF's", die durch die Verwendung von 'breakOut' verursacht werden können. Auf der anderen Seite, heute habe ich etwas Neues gelernt, also danke, dass du es aufgezeigt hast :) –

1

Mehrere Links hier, auf die mich entweder andere Leute hingewiesen haben oder die ich später herausgefunden habe, indem ich sie in einer einzigen Antwort für meine zukünftige Referenz zusammengestellt habe.

+0

Danke für die Erwähnung, aber Gábor's Antwort ist älter. Ich habe gerade versucht, schnell nach einem Duplikat zu suchen und die verknüpfte verwandte Frage gefunden. –

Verwandte Themen