使用转置将完整外部联接样式中的列表合并 [英] Using transpose to merge lists in full outer join style

查看:88
本文介绍了使用转置将完整外部联接样式中的列表合并的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图返回一个加入的列表。但是,连接必须像数据库完全外连接一样。



例如,给出以下内容:

  def x = [[a:1,b:2],[a:1,b:3],[a:2,b:4],[a:3,b:5 ]] 
def y = [[f:10,b:2,g:7],[f:100,b:3,g:8],[f:20,b:4,g:9 ],[f:20,b:6,g:9]]

我想返回:

  [[a:1,b:2,f:10,g:7],[a:1, b:3,f:100,g:8],[a:2,b:4,f:20,g:9],[a:3,b:5],[a:3,b: f:20,g:9]] 

在前面的问题中,有人向我展示了如何使用转置加入列表。

  def z = [x,y] .transpose()。collect {a,b  - > a + b} 
println z

但是输出错过 [a:3,b:5] 。见下面。

  [[a:1,b:2,f:10,g:7],[a:1 ,b:3,f:100,g:8],[a:2,b:4,f:20,g:9],[a:3,b:6,f:20,g:9]] 

有人可以帮助我理解所需的表达式,并帮助我理解原始表达式为什么不是工作?

解决方案

首先让我们解释 GroovyCollections.transpose(列表列表) 可以解决这个问题。对于给定的输出

  def x = [[a:1,b:2],[a:1,b:3] ,[a:2,b:4],[a:3,b:5]] 
def y = [[f:10,b:2,g:7],[f:100,b: 3,g:8],[f:20,b:4,g:9],[f:20,b:6,g:9]]

$ b表达式

$ $ p $ $ $ $ $ $ $ $ $ $ $ b

创建一个配对列表:

  [
[[a:1,b:2],[f:10,b:2,g:7]],
[[a:1,b: 3],[f:100,b:3,g:8]],
[[a:2,b:4],[f:20,b:4,g:9]],
[[a:3,b:5],[f:20,b:6,g:9]]
]

如果我们将它与您期望得到的列表进行比较,则可以使用

pre $ def $ def $ = [a:1,b:2,f:10,g:7],[a:1,b:3,f:100,g:8],[a:2,b:4,f:20,g :9],[a:3,b:5],[a:3,b:6,f:20,g:9]]

我们可以看到它包含的不是4,而是5个元素。有一个隐藏的需求可以在调查所需结果后找到:如果有一对至少有一个公共密钥的两个映射,但每个对元素有两个不同的值,则不要合并这两个对,但创建两个映射,其中第一个映射是来自 x 的映射并且不变,第二个映射从 x y



如何检查两张地图是否至少有一个不同的公钥值?



我们可以使用 Collection.intersect(Collection right) 。但是我们必须比较两个交点:


  1. 交点 Map.keySet() key

  2. 来自两个地图的 Map.Entry 元素的交集

第一个路口会告诉我们两张地图是否有相同的钥匙,而第二个路口会告诉我们他们是否存储了相同的值。如果两个表达式的计算结果都是 true ,我们将它们与 a + b 合并,就像您提到的例子(如果两个地图没有共同的键,我们也会使用相同的方法)。但是,如果两个地图都有非空的键交集,而地图条目的交集不等于第一个交集的结果,我们将使用 [a,a + b] 我们将最终得到 .flatten()结果。下面你可以找到一个Groovy代码,它可以完成我刚才描述的内容:

  def x = [[a:1,b: 2],[a:1,b:3],[a:2,b:4],[a:3,b:5]] 
def y = [[f:10,b:2, g:7],[f:100,b:3,g:8],[f:20,b:4,g:9],[f:20,b:6,g:9]]
def expected = [[a:1,b:2,f:10,g:7],[a:1,b:3,f:100,g:8],[a:2,b: f:20,g:9],[a:3,b:5],[a:3,b:6,f:20,g:9]]

def shareSameKeyWithSameValue(Map< String,?> a,Map< String,?> b){
final Set< String> keysIntersectionFromEntries =(a.entrySet()。intersect(b.entrySet()))。key as Set
final Set< String> keysIntersection = a.keySet()。intersect(b.keySet())
return!keysIntersectionFromEntries.isEmpty()&& keysIntersectionFromEntries.containsAll(keysIntersection)
}

def result = [x,y] .transpose()。collect {a,b - >
shareSameKeyWithSameValue(a,b)? a + b:[a,a + b]
} .flatten()

断言结果==预期的

我希望它有帮助。


I'm trying to return a joined list. But the join has to be like a database full outer join.

For example given the following:

def x = [ [a:1, b:2], [a:1, b:3], [a:2, b:4], [a:3, b:5] ]
def y = [ [f:10, b:2, g:7], [f:100, b:3, g:8], [f:20, b:4, g:9], [f:20, b:6, g:9]  ]

I'd like to return:

[[a:1, b:2, f:10, g:7], [a:1, b:3, f:100, g:8], [a:2, b:4, f:20, g:9], [a:3, b:5], [a:3, b:6, f:20, g:9]]

In a previous question someone showed me how to use transpose to join the lists.

def z = [x,y].transpose().collect { a, b -> a + b }
println z​

But the output from that misses [a:3, b:5] from the expected output. See below.

[[a:1, b:2, f:10, g:7], [a:1, b:3, f:100, g:8], [a:2, b:4, f:20, g:9], [a:3, b:6, f:20, g:9]]

Could someone help me with the required expression and assist me in my understanding of why the original expression was not working?

解决方案

Firstly let's explain how GroovyCollections.transpose(List lists) works to solve this problem. For given output

def x = [ [a:1, b:2], [a:1, b:3], [a:2, b:4], [a:3, b:5] ]
def y = [ [f:10, b:2, g:7], [f:100, b:3, g:8], [f:20, b:4, g:9], [f:20, b:6, g:9] ]

expression

[x,y].transpose()

creates a list of pairs:

[
    [[a:1, b:2], [f:10, b:2, g:7]],
    [[a:1, b:3], [f:100, b:3, g:8]],
    [[a:2, b:4], [f:20, b:4, g:9]],
    [[a:3, b:5], [f:20, b:6, g:9]]
]

If we compare it with a list you expect to get

def expected = [[a:1, b:2, f:10, g:7], [a:1, b:3, f:100, g:8], [a:2, b:4, f:20, g:9], [a:3, b:5], [a:3, b:6, f:20, g:9]]

we can see that it contains not 4, but 5 elements. There is one hidden requirement that can be found after investigating desired result: if there is a pair of two maps that has at least one common key, but with two different values for each pair element, then don't merge those two pairs, but create two maps instead, where first map is a map that comes from x and is unchanged and second one is a result of merging maps from x and y.

How to check if two maps have at least one common key with different values?

We can use Collection.intersect(Collection right) for that. But we have to compare two intersections:

  1. Intersection of Map.keySet() keys
  2. Intersection of Map.Entry elements from both maps

First intersection will tell us if there are same keys in both maps, while the second intersection will tell us if they store the same value. If both expressions evaluate to true, we will merge them with a + b as it was in the example you have mentioned (we will also use the same method if both maps does not have any keys in common). But if both maps have non-empty intersection of keys while intersection of map entries is not equal to the result of first intersection we will merge these maps using [a, a+b] and we will .flatten() the result eventually. Below you can find a Groovy code that does what I have just described:

def x = [[a: 1, b: 2], [a: 1, b: 3], [a: 2, b: 4], [a: 3, b: 5]]
def y = [[f: 10, b: 2, g: 7], [f: 100, b: 3, g: 8], [f: 20, b: 4, g: 9], [f: 20, b: 6, g: 9]]
def expected = [[a: 1, b: 2, f: 10, g: 7], [a: 1, b: 3, f: 100, g: 8], [a: 2, b: 4, f: 20, g: 9], [a: 3, b: 5], [a: 3, b: 6, f: 20, g: 9]]

def shareSameKeyWithSameValue(Map<String, ?> a, Map<String, ?> b) {
    final Set<String> keysIntersectionFromEntries = (a.entrySet().intersect(b.entrySet())).key as Set
    final Set<String> keysIntersection = a.keySet().intersect(b.keySet())
    return !keysIntersectionFromEntries.isEmpty() && keysIntersectionFromEntries.containsAll(keysIntersection)
}

def result = [x, y].transpose().collect { a, b ->
    shareSameKeyWithSameValue(a, b) ? a + b : [a, a + b]
}.flatten()

assert result == expected

I hope it helps.

这篇关于使用转置将完整外部联接样式中的列表合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆