# Grab first successful pair from a list of maps

I have a function that parses geographic coordinates through a list of different providers. In this case I want to look up two addresses. The main problem of this question is - given a List of of Geocode Service -> Resolved Address mappings, find the first successful pair that has a valid resolved address.

So each address results in a map(provider -> result). I'm given a list of them, and need to find the a successful pair from the list e.g provider1 from the first address and provider1 from the second address. I can't compare the resolved addresses if the providers do not match.

For example, the best scenario is that the addresses are perfect. I can use the head map entry of the first address and query the map entry for the second address. Then compare their values. However, it's rarely that simple.

I started out with a foldLeft, but I feel that can be inefficient if it matches successfully immediately.

val result: List[Map[GeoProviders.GeoProvider, Either[GeoCodeErrors.GeocodeError, PostalAddress]]]
result match {
result match {
case Some(_) => result
case None =>
case (Some(firstCoord), Some(secondCoord)) => {
Some(haversineDistance((firstCoord.latitude, firstCoord.longitude), (secondCoord.latitude, secondCoord.longitude)))
}
case _ => None
}
}
}
}
})


You can use find to avoid folding over an entire map, something like:

map1.find {
map2.get(k) match {
case _ => false
}
case _ => false
} match {
case _ => None
}


(I renamed first/secondAddressOption to map1/map2 to save some typing)

An alternative approach, which doesn't necessarily improve performance but does make the code shorter and more reusable, is to create a method that combines two maps by key:

def combineMaps[K, V](map1: Map[K, V], map2: Map[K, V]): Map[K, List[V]] =
// To improve performance, compare the sizes of map1 and map2
// and fold over the smaller map.
map1.foldLeft(map2.mapValues(List(_))) {
case (map2, (k, x)) => map2.updated(k, x :: map2.get(k).toList.flatten)
}


Then use collectFirst on the combined map:

combineMaps(map1, map2).collectFirst {