2010-05-21 16 views
9

¿Hay una mejor manera de hacer esto:¿La mejor manera de puntuar y sumar en Scala?

val totalScore = set.foldLeft(0)(_ + score(_)) 

o esto:

val totalScore = set.toSeq.map(score(_)).sum 

Creo que es una operación bastante común por lo que se esperaba algo más elegante como:

val totalScore = set.sum(score(_)) 
+1

Las primeras dos piezas de código hacen cosas diferentes. Vea mi comentario a la respuesta de Daniel C. Sobral. – dsg

+0

Gracias @dsg, lo cambié. – adam77

Respuesta

17

Bueno, hay formas alternativas de escribirlo:

val totalScore = set.toSeq.map(score(_)).sum 
val totalScore = set.toSeq.map(score).sum 
val totalScore = set.toSeq map score sum 

El último de ellos puede requerir un punto y coma al final si la siguiente línea no comienza con una palabra clave. También se puede usar .view en lugar de .toSeq, lo que evitaría asignar una colección temporal. Sin embargo, no estoy seguro de que el comportamiento actual de .view (de mostrar elementos repetidos) sea el correcto.

+1

Parece la solución más simple y adecuada. Preferiría leer esto en lugar de tener una función que incluye hacer el mapeo. – ziggystar

+3

Una preocupación legítima con el enfoque de dos pasos puede ser el rendimiento: crea una segunda lista solo para sumarla. Sin embargo, puede usar una vista para evitar esta sobrecarga: 'set.view.map (score) .sum'. Separar las preocupaciones del mapeo y la sumatoria evita una explosión de métodos en la biblioteca estándar. Si lo haces con frecuencia, puedes agregar 'mapAndSum' a tu propio código. – retronym

+0

¿Alguien tiene un enlace a alguna documentación sobre vistas? – adam77

1

Más sencillo :

scala> val is1 = Set(1, 4, 9, 16) 
is1: scala.collection.immutable.Set[Int] = Set(1, 4, 9, 16) 
scala> is1.reduceLeft(_ + _) 
res0: Int = 30 

Con su método de puntuación:

scoreSet.reduceLeft(_ + score(_)) 

advertencia, sin embargo, esto no se está reduciendo la colección está vacía mientras veces no:

scala> val is0 = Set[Int]() 
is0: scala.collection.immutable.Set[Int] = Set() 

scala> is0.foldLeft(0)(_ + _) 
res1: Int = 0 
+3

Esto no funcionará. El tipo de la colección es diferente del tipo de resultado (que es el motivo de la llamada a 'puntuación '), por lo que' reduceLeft' no es una opción. –

1

Alternativamente, la sobrecarga de Seq#sum que se lleva a una conversión implícita a Numeric podría usarse si el tipo de la colección a calificar/sumar no tiene un operador adicional. Sin embargo, debido a que es un parámetro de conversión implícito, no se aplicará a menos que sea necesario para realizar la verificación de tipo de cierre reducido.

5

Seq.sum no toma una función que podría utilizarse para calificar la suma. Se podría definir una conversión implícita que "proxenetas" Traversable:

implicit def traversableWithSum[A](t: Traversable[A])(implicit m: Numeric[A]) = new { 
    def sumWith(f: A => A) = t.foldLeft(m.zero)((a, b) => m.plus(a, f(b))) 
} 

def score(i: Int) = i + 1 

val s = Set(1, 2, 3) 

val totalScore = s.sumWith(score _) 
println(totalScore) 
=> 9 

Tenga en cuenta que el rasgo Numeric sólo existe en Scala 2.8.

+2

Michel, me gusta su solución y pensé que podría hacerlo un poco más genérico al permitir que el puntaje trabaje en un objeto, como "Juego" y devuelva un valor numérico: deftraversable implícitaconSum [A] (t: Traversable [A]) = nuevo { def sumWith [B] (f: A => B) (implícito m: Numérico [B]): B = t.foldLeft (m.zero) ((a, b) => m .plus (a, f (b))) } – Eric

Cuestiones relacionadas