Scala - 按公共元素合并两个元组列表

Dad*_*dou 3 scala group-by list scala-collections

如何合并两个模拟Chasles 关系的元组列表?

(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"))
Run Code Online (Sandbox Code Playgroud)

预期结果是:

val result = List(("Dan", "3"), ("Dan", "1"), ("Dan", "2"), ("Bart", "1"))
Run Code Online (Sandbox Code Playgroud)

hoy*_*and 6

您基本上想要考虑第一个列表中的一个元素和第二个列表中的一个元素的所有对,并保留“b”元素匹配的那些。

换句话说,我们想要映射l1,并且在该映射内部映射l2,这意味着我们考虑每个列表中元素的所有对,所以类似于:

l1.map(x => l2.map(y => (x,y))
Run Code Online (Sandbox Code Playgroud)

但这并不完全正确,因为我们现在有一个List[List[((String, String),(String,String))]]——我们需要平面地图:

l1.flatMap(x => l2.map(y => (x,y)))
Run Code Online (Sandbox Code Playgroud)

现在我们必须过滤以仅保留我们想要的对并进行整理:

l1.flatMap(x => l2.map(y => (x,y)))
  .filter{ case ((_,y),(b,_)) => y == b }
  .map {case ((x, _),(_,c)) => (x,c) }
Run Code Online (Sandbox Code Playgroud)

这给了我们

List((Dan,3), (Dan,1), (Dan,2), (Bart,1))
Run Code Online (Sandbox Code Playgroud)

这是一团丑陋的混乱,所以我们可以稍微整理一下——让l2我们在原始文件中进行过滤flatmap并在那里构建结果,这样我们就不必处​​理元组的元组:

l1.map{ case (x,y) => 
    l2.filter{ case (b, _) => y == b}
      .map{ case (_, c) => (x, c)} }
Run Code Online (Sandbox Code Playgroud)

这是更容易阅读for理解的情况之一:

for {
  (x, y) <- l1
  (b, c) <- l2
  if y == b
} yield (x,c)
Run Code Online (Sandbox Code Playgroud)