[英]Scala - Merge two lists of tuples by common elements
How to merge two lists of tuples that simulates Chasles' Relation? 如何合并两个模拟 Chasles关系的元组列表?
(a, b), (b, c) => (a, c) (a,b),(b,c)=>(a,c)
Here is an example: 这是一个例子:
val l1 = List(("Dan", "b"), ("Dan","a"), ("Bart", "c"))
val l2 = List(("a", "1"), ("c", "1"), ("b", "3"), ("a", "2"))
Expected result would be: 预期结果将是:
val result = List(("Dan", "3"), ("Dan", "1"), ("Dan", "2"), ("Bart", "1"))
You basically want to consider all pairs of one element from the first list and one from the second and keep those where the "b" elements match. 基本上,您要考虑第一个列表中所有元素对和第二个列表中所有元素对,并保持匹配那些“ b”个元素。
In other words, we want to map over l1
and, inside that map, map over l2
, meaning we consider all the pairs of an element from each list, so something like: 换句话说,我们要在
l1
进行映射,并且在该映射内,在l2
上进行映射,这意味着我们考虑了每个列表中元素的所有对,因此类似:
l1.map(x => l2.map(y => (x,y))
That's not quite right, though, since we now have a List[List[((String, String),(String,String))]]
--we needed to flatmap: 不过,这还不太正确,因为我们现在有了一个
List[List[((String, String),(String,String))]]
我们需要平面映射:
l1.flatMap(x => l2.map(y => (x,y)))
Now we have to filter to keep just the pairs we want and tidy up: 现在我们必须进行过滤以保持我们想要的对并整理:
l1.flatMap(x => l2.map(y => (x,y)))
.filter{ case ((_,y),(b,_)) => y == b }
.map {case ((x, _),(_,c)) => (x,c) }
which gives us 这给了我们
List((Dan,3), (Dan,1), (Dan,2), (Bart,1))
That was kind of an ugly mess, so and we can tidy it up a bit--let's filter l2
in our original flatmap
and build the result there, so we don't have to juggle the tuple of tuples: 那是一个丑陋的混乱,所以我们可以对其进行整理—让我们在原始
flatmap
过滤器l2
并在那里建立结果,因此我们不必flatmap
元组的元组:
l1.map{ case (x,y) =>
l2.filter{ case (b, _) => y == b}
.map{ case (_, c) => (x, c)} }
This is one of those cases where it's easier to read a for
comprehension: 这是那些情况下更易于阅读一个
for
理解:
for {
(x, y) <- l1
(b, c) <- l2
if y == b
} yield (x,c)
For each tuple in l1
you can filter l2
to select the tuples with the matching first element: 对于
l1
每个元组,您可以过滤l2
以选择具有匹配的第一个元素的元组:
def join[A, B, C](l1: List[(A, B)], l2: List[(B, C)]): List[(A, C)] = {
for {
(key, subkey) <- l1
value <- l2.collect { case (`subkey`, value) => value }
} yield key -> value
}
You could also convert l2
into a Map
beforehand for better selection performance: 您也可以事先将
l2
转换为Map
以获得更好的选择性能:
def join[A, B, C](l1: List[(A, B)], l2: List[(B, C)]): List[(A, C)] = {
val valuesMap = l2.groupBy(_._1)
for {
(key, subkey) <- l1
(_, value) <- valuesMap.getOrElse(subkey, Nil)
} yield key -> value
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.