如何合并模拟 Chasles'Lissore的两个元组列表?
(a,b),(b,c)=> (a,c)
以下是一个例子:
val l1 = List(("Dan", "b"), ("Dan","a"), ("Bart", "c"))
val l2 = List(("a", "1"), ("c", "1"), ("b", "3"), ("a", "2"))
预期结果将是:
val result = List(("Dan", "3"), ("Dan", "1"), ("Dan", "2"), ("Bart", "1"))
答案 0 :(得分:4)
你基本上想要考虑第一个列表中的一个元素和第二个列表中的一个元素,并保留“b”元素匹配的元素。
换句话说,我们希望映射l1
并在该地图内映射l2
,这意味着我们会考虑每个列表中所有元素的对,所以类似于:
l1.map(x => l2.map(y => (x,y))
但这不太对,因为我们现在有一个List[List[((String, String),(String,String))]]
- 我们需要平面图:
l1.flatMap(x => l2.map(y => (x,y)))
现在我们必须过滤以保持我们想要的对并整理:
l1.flatMap(x => l2.map(y => (x,y)))
.filter{ case ((_,y),(b,_)) => y == b }
.map {case ((x, _),(_,c)) => (x,c) }
给了我们
List((Dan,3), (Dan,1), (Dan,2), (Bart,1))
这是一个丑陋的混乱,所以我们可以稍微整理一下 - 让我们在我们原来的l2
中过滤flatmap
并在那里建立结果,所以我们不必玩弄元组的元组:
l1.map{ case (x,y) =>
l2.filter{ case (b, _) => y == b}
.map{ case (_, c) => (x, c)} }
这是一种更容易阅读for
理解的案例之一:
for {
(x, y) <- l1
(b, c) <- l2
if y == b
} yield (x,c)
答案 1 :(得分:2)
对于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
}
您也可以事先将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
}