Pregunta

Supongamos que tengo

val foo : Seq[Double] = ...
val bar : Seq[Double] = ...

y deseo para producir una SEC donde el baz (i) = foo (i) + bar (i). Una forma que se me ocurre de hacerlo es

val baz : Seq[Double] = (foo.toList zip bar.toList) map ((f: Double, b : Double) => f+b)

Sin embargo, esto se siente tanto fea e ineficiente - Tengo que convertir ambos SEQs a listas (que estalla con las listas perezoso), crear esta lista temporal de tuplas, sólo para trazar sobre ella y dejar que sea GCed. Tal vez arroyos resolver el problema perezoso, pero en cualquier caso, esto se siente como innecesariamente feo. En Lisp, la función de mapa sería asignar a través de múltiples secuencias. Me gustaría escribir

(mapcar (lambda (f b) (+ f b)) foo bar)

Y no hay listas temporales conseguirían creado en cualquier lugar. ¿Hay una función de mapa-over-múltiples listas en Scala, o se combina con cremallera desestructuración realmente la forma 'correcta' de hacer esto?

¿Fue útil?

Solución

La función que desea se llama zipWith, pero no es una parte de la biblioteca estándar. Será en 2.8. (ACTUALIZACIÓN: Al parecer no, ver comentarios)

foo zipWith((f: Double, b : Double) => f+b) bar

este billete Trac .

Otros consejos

En Scala 2.8:

val baz = (foo, bar).zipped map (_ + _)

Además, funciona desde hace más de dos operandos de la misma manera. Es decir. A continuación, puede seguir esto con:

(foo, bar, baz).zipped map (_ * _ * _)

Pues eso, la falta de cremallera, es una deficiencia en la Scala de 2.7 Sec. Scala 2.8 tiene un diseño de la colección bien pensado, para reemplazar la forma ad-hoc de las colecciones presentes en 2,7 llegaron a ser (tenga en cuenta que no fueron creados al mismo tiempo, con un diseño unificado).

Ahora, cuando se quiere evitar la creación de colección temporal, se debe utilizar "proyección" en la Scala 2.7, o "vista" en la Scala 2.8. Esto le dará un tipo de colección para los que ciertas instrucciones, particularmente mapa, flatMap y el filtro, no son estrictas. En Scala 2.7, la proyección de una lista es una corriente. En Scala 2.8, hay una SequenceView de una secuencia, pero hay una zipWith allí mismo en la secuencia, usted ni siquiera lo necesita.

Una vez dicho esto, como se ha mencionado, la JVM está optimizado para manejar las asignaciones de objetos temporales, y, cuando se ejecuta en modo de servidor, la optimización en tiempo de ejecución puede hacer maravillas. Por lo tanto, no optimizar prematuramente. Probar el código en las condiciones que se llevará a cabo - y si usted no ha planeado para ejecutarlo en modo de servidor, a continuación, volver a pensar que si se espera que el código sea larga ejecución, y Optmize cuándo / dónde / si es necesario <. / p>

Editar

Lo que en realidad va a estar disponible en Scala 2.8 es la siguiente:

(foo,bar).zipped.map(_+_)

Una lista perezoso no es una copia de una lista - que es más como un solo objeto. En el caso de una implementación postal perezoso, cada vez que se pidió para el siguiente elemento, se agarra un elemento de cada una de las dos listas de entrada y crea una tupla de ellos, y luego romper la tupla de separación, con el reconocimiento de patrones en su lambda.

Así que nunca hay una necesidad de crear una copia completa de la lista (s) de entrada entera antes de comenzar a operar en ellos. Todo se reduce a un patrón de asignación muy similar a cualquier aplicación que se ejecuta en la JVM -. Un montón de asignaciones de muy corta duración, pero pequeñas, que la JVM está optimizado para hacer frente a

Actualización: para ser claro, tiene que ser el uso de corrientes (listas perezosas) no Listas. flujos de Scala tienen una cremallera que funciona de la manera perezosa, y por lo que no deben ser cosas convirtiendo en listas.

Lo ideal sería que el algoritmo debe ser capaz de trabajar en dos infinito arroyos sin volar (suponiendo que no hace ningún folding, por supuesto, pero sólo lee y genera corrientes).

ACTUALIZACIÓN: Se ha señalado (en los comentarios) que esta "respuesta" en realidad no aborda la cuestión que se plantea. Esta respuesta mapeará sobre cada combinación de foo y bar, produciendo N x M elementos, en vez de la min (M, N) a lo solicitado . Por lo tanto, esto es mal , pero dejó para la posteridad, ya que es una buena información.


La mejor manera de hacerlo es con flatMap combinado con map. Código habla más que mil palabras:

foo flatMap { f => bar map { b => f + b } }

Esto producirá una sola Seq[Double], tal y como era de esperar. Este patrón es tan común que Scala en realidad incluye un poco de magia sintáctica que prevé su aplicación:

for {
  f <- foo
  b <- bar
} yield f + b

O, de forma alternativa:

for (f <- foo; b <- bar) yield f + b

La sintaxis for { ... } es realmente la forma más idiomática para hacer esto. Puede seguir añadiendo cláusulas del generador (por ejemplo b <- bar) según sea necesario. Por lo tanto, si de repente se convierte en Seqs que debe asignar más, puede escalar fácilmente su sintaxis, junto con sus requisitos (para acuñar una frase).

Cuando se enfrentó a una tarea similar, añadí la siguiente pimp a Iterables:

implicit class IterableOfIterablePimps[T](collOfColls: Iterable[Iterable[T]]) {
  def mapZipped[V](f: Iterable[T] => V): Iterable[V] = new Iterable[V] {
    override def iterator: Iterator[V] = new Iterator[V] {
      override def next(): V = {
        val v = f(itemsLeft.map(_.head))
        itemsLeft = itemsLeft.map(_.tail)
        v
      }

      override def hasNext: Boolean = itemsLeft.exists(_.nonEmpty)

      private var itemsLeft = collOfColls
    }
  }
}

Tener esto, se puede hacer algo como:

val collOfColls = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
collOfColls.mapZipped { group =>
  group // List(1, 4, 7), then List(2, 5, 8), then List(3, 6, 9)
}

Tenga en cuenta que usted debe considerar cuidadosamente tipo de colección pasada como Iterable anidado, ya tail y head se llamará recurrentemente en él. Por lo tanto, lo ideal es que pasar Iterable[List] o otra colección con tail rápido y head.

Además, este código de espera colecciones anidadas del mismo tamaño. Ese fue mi caso de uso, pero sospecho que esto puede ser mejorado, si es necesario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top