2009-06-21 11 views
10

Estoy aprendiendo Scala y explorando algunos de los aspectos funcionales del lenguaje.Agregue valores de lista en Scala

Comenzando con una lista de objetos que contienen dos parámetros nocionales y de moneda, ¿cómo puedo agregar el total nocional por moneda?

//sample data 
val t1 = new Trade("T150310", 10000000, "GBP"); 
val t2 = new Trade("T150311", 10000000, "JPY"); 
val t3 = new Trade("T150312", 10000000, "USD"); 
val t4 = new Trade("T150313", 100, "JPY"); 
val t5 = new Trade("T150314", 1000, "GBP"); 
val t6 = new Trade("T150315", 10000, "USD"); 

val trades = List(t1, t2, t3, t4, t5, t6); 

Respuesta

4

escribí un grupo mediante una simple operación (en realidad un Groupabletrait con una conversión implícita de un Iterable), que le permitirían agrupar sus oficios por su currency:

trait Groupable[V] extends Iterable[V] { 
    def groupBy(f: V => K): MultiMap[K, V] = { 
    val m = new mutable.HashMap[K, Set[V]] with mutable.MultiMap[K, V] 
    foreach { v => m add (f(v), v) } //add is defined in MultiMap 
    m 
    } 
} 
implicit def it2groupable(it: Iterable[V]): Groupable[V] = new Groupable[V] { 
    def elements = it.elements 
} 

Así Groupable es simplemente proporcionando una forma de extraer una clave de cada artículo en un Iterable y luego agrupando todos los artículos que tienen la misma clave. Así, en su caso:

//mm is a MultiMap[Currency, Trade] 
val mm = trades groupBy { _.currency } 

ahora se puede hacer una muy simple mapElements (mm es una Map) y un foldLeft (o /: - bien vale la pena entender el operador foldLeft ya que permite agregaciones muy concisas sobre colecciones) a obtener la suma:

val sums: Map[Currency, Int] = mm mapElements { ts => 
    (0 /: ts) { (sum,t) => sum + t.notional } 
} 

Disculpas si he cometido algunos errores en esa última línea. ts son los valores de mm, que son (por supuesto) Iterable[Trade].

+0

Lo sentimos, por alguna razón que leí "El comercio", pero oí "tupla" en mi respuesta original. ¡Lo he editado ahora! –

16

Si utiliza el maletero, la maquinaria ya está allí. groupBy se define en Traversable y la suma se puede aplicar directamente a la lista, no es necesario escribir un fold.

scala> trades groupBy (_.currency) map { case (k,v) => k -> (v map (_.amount) sum) } 
res1: Iterable[(String, Int)] = List((GBP,10001000), (JPY,10000100), (USD,10010000)) 
+0

¿Eso viene en 2.8? –

+0

¿Y puede explicar de dónde viene la función suma? –

+0

Sí, lo que ahora es trunk es lo que será 2.8. El método de suma se define en NumericTraversableOps, que no es una clase de la que necesites saber, pero básicamente agrega métodos a Traversable de forma implícita en función de la presencia de un Numeric [T], que a su vez define "agregar" suma puede ser genéricamente definido. – extempore

Cuestiones relacionadas