The function you're looking for is usually called zipWith. It's unfortunately not provided in the standard libraries, but it's pretty easy to write:
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
  }
This will traverse only once, since the implementations for zip and map on iterators are fully lazy.
But why stop at Iterable? This has an even more general form. We could declare an interface for all data structures that can be zipped this way.
trait Zip[F[_]] {
  def zipWith[A,B,C](f: (A,B) => C, a: F[A], b: F[B]): F[C]
}
For example, we can zip functions:
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))
}
There turns out to be an even more general expression of this type. In general, type constructors that allow an implementation of this interface are 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]
}
An implementation of zipWith is then just this:
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)
This generalises to functions of any arity:
  m.ap(m.ap(m.ap(m.map(f,a), b), c), d)
The Scalaz library provides Applicative instances for a lot of data structures in the standard library. It also does library pimping so that you can just do this:
import scalaz._
import Scalaz._
List(1,2,3).zipWith(List(2,3,4))(x: Int, y: Int) => x * y)
Also, convenient syntax is provided for ap. In Scalaz, this function is called <*>:
def zipWith[F[_]:Applicative,A,B,C](f: A => B => C, a: F[A], b: F[B]) =
  (a map f) <*> b