La funzione che stai cercando è solitamente denominata zipWith
. Non è purtroppo previsto nelle librerie standard, ma è abbastanza facile da scrivere:
def zipWith[A,B,C](f: (A,B) => C, a: Iterable[A], b: Iterable[B]) =
new Iterable[C] {
def elements = (a.elements zip b.elements) map f.tupled
}
Ciò attraversare solo una volta, dal momento che le implementazioni per zip
e map
su iteratori sono completamente pigri.
Ma perché fermarsi allo Iterable
? Questo ha una forma ancora più generale. Potremmo dichiarare un'interfaccia per tutte le strutture di dati che possono essere compresse in questo modo.
trait Zip[F[_]] {
def zipWith[A,B,C](f: (A,B) => C, a: F[A], b: F[B]): F[C]
}
Ad esempio, possiamo comprimere funzioni:
trait Reader[A] {
type Read[B] = (A => B)
}
def readerZip[T] = new Zip[Reader[T]#Read] {
def zipWith[A,B,C](f: (A,B) => C, a: T => A, b: T => B): T => C =
(t: T) => f(a(t),b(t))
}
Ci risulta essere un'espressione ancora più generale di questo tipo. In generale, costruttori di tipo che consentono un'implementazione di questa interfaccia sono applicative functors
trait Applicative[F[_]] {
def pure[A](a: A): F[A]
def map[A,B](f: A => B, a: F[A]): F[B]
def ap[A,B](f: F[A => B], a: F[A]): F[B]
}
Un'implementazione zipWith viene poi solo questo:
def zipWith[F[_],A,B,C](f: A => B => C, a: F[A], b: F[B])
(implicit m: Applicative[F]) =
m.ap(m.map(f,a), b)
Questo generalizza a funzioni di qualsiasi arietà:
m.ap(m.ap(m.ap(m.map(f,a), b), c), d)
La libreria Scalaz fornisce istanze Applicative per molte strutture di dati nella libreria standard. Inoltre, viene fornita una comoda sintassi per ap
. In Scalaz, questa funzione è chiamata <*>
:
def zipWith[F[_]:Applicative,A,B,C](f: A => B => C, a: F[A], b: F[B]) =
(a map f) <*> b
Se 'zip()' non funziona, cosa è necessario fare diversamente? –
figlio di un ... zip. Agli ordini! Non ci ho nemmeno pensato. Perché non pubblichi così posso svenderlo. – wheaties
Lascerò @Mike per rispondere, ma puoi fare 'list1 zip list2' e anche' (list1, list2) .zipped'. Quest'ultima, solo Scala 2.8, non crea una collezione temporanea. Inoltre, si può fare 'list1.view zip list2' o' list1.projection zip list2' su Scala 2.8 e 2.7 rispettivamente per evitare di creare collezioni temporanee. –