Non si può davvero farlo come one-liner, quindi dovresti essere sicuro di averne bisogno prima di scrivere qualcosa di più elaborato come questo (scritto da una visione piuttosto performante visto che hai chiesto "efficiente"):
final case class Var[A](var value: A) { }
def multifold[A,B,C](xs: Traversable[A])(f: A => B)(zero: C)(g: (C,A) => C) = {
import scala.collection.JavaConverters._
val m = new java.util.HashMap[B, Var[C]]
xs.foreach{ x =>
val v = {
val fx = f(x)
val op = m.get(fx)
if (op != null) op
else { val nv = Var(zero); m.put(fx, nv); nv }
}
v.value = g(v.value, x)
}
m.asScala.mapValues(_.value)
}
(a seconda del caso d'uso si potrebbe desiderare di mettere in valigia in una mappa immutabile, invece nell'ultimo passaggio.) Ecco un esempio di esso in azione:
scala> multifold(List("salmon","herring","haddock"))(_(0))(0)(_ + _.length)
res1: scala.collection.mutable.HashMap[Char,Int] = Map(h -> 14, s -> 6)
Ora, si potrebbe notare qualcosa strano qui: sto usando una HashMap Java. Questo perché le HashMaps di Java sono 2-3 volte più veloci di quelle di Scala. (Puoi scrivere la cosa equivalente con Scala HashMap, ma in realtà non rende le cose più veloci del tuo originale.) Di conseguenza, questa operazione è 2-3 volte più veloce di quanto hai postato. Ma a meno che tu non sia sottoposto a forti pressioni sulla memoria, la creazione delle collezioni transitori non ti fa veramente molto male.
fonte
2013-03-20 17:12:15
@sschaef Puoi spiegare la ragione per cambiare "qual è il modo migliore" per "È possibile e se sì come"? Deve essere possibile (completezza di Turing) ed è facile trovare un modo klunky per farlo. Faccio anche la domanda sgrammaticata –
"qual è il modo migliore" è un cattivo formato per una domanda, normalmente non si può rispondere in modo definitivo. Ma accetto il rollback dopo aver ripensato alla modifica, non ha migliorato la domanda. – sschaef