Поскольку OP любопытно посмотреть, как мы будем использовать ленивые коллекции или пользовательские фолды для того же, я включил отдельный ответ в эти реализации.
Первая реализация использует ленивые коллекции. Обратите внимание, что у ленивых коллекций плохие свойства кэша, поэтому на практике часто не имеет смысла использовать ленивые коллекции в качестве микрооптимизации. Хотя отложенные коллекции будут минимизировать количество проходов данных, как уже упоминалось, базовая структура данных не имеет хорошей локализации кэша. Чтобы понять, почему отложенные коллекции минимизируют количество проходов, которые вы делаете над данными, прочитайте главу 5 Функциональное программирование в Scala.
object LazyZipTest extends App{
val incomingUrl = List("users", "profile", "12345", "extra").view
val urlToCompare = List("users", "profile", ":id").view
val list1 = incomingUrl.map(Some(_))
val list2 = urlToCompare.map(Some(_))
val zipped = list1.zipAll(list2, None, None)
println(zipped)
}
Во второй реализации используется пользовательское свертывание для go над списками только один раз. Поскольку мы добавляем в конец нашей структуры данных, мы хотим использовать IndexedSeq, а не List. Вы все равно должны редко использовать List. В противном случае, если вы собираетесь конвертировать из List в IndexedSeq, вы фактически делаете один дополнительный проход по данным, и в этом случае вы можете не беспокоиться и просто использовать простую реализацию, которую я уже написал в другом ответе.
Вот пользовательский фолд.
object FoldTest extends App{
val incomingUrl = List("users", "profile", "12345", "extra").toIndexedSeq
val urlToCompare = List("users", "profile", ":id").toIndexedSeq
def onePassZip[T, U](l1: IndexedSeq[T], l2: IndexedSeq[U]): IndexedSeq[(Option[T], Option[U])] = {
val folded = l1.foldLeft((l2, IndexedSeq[(Option[T], Option[U])]())) { (acc, e) =>
acc._1 match {
case x +: xs => (xs, acc._2 :+ (Some(e), Some(x)))
case IndexedSeq() => (IndexedSeq(), acc._2 :+ (Some(e), None))
}
}
folded._2 ++ folded._1.map(x => (None, Some(x)))
}
println(onePassZip(incomingUrl, urlToCompare))
println(onePassZip(urlToCompare, incomingUrl))
}
Если у вас есть какие-либо вопросы, я могу ответить на них в разделе комментариев.