Groovy:与 a.intersect( b ) 和 b.intersect( a ) 的区别

发布于 2024-12-04 04:01:24 字数 1499 浏览 4 评论 0原文

为什么在 Groovy 中,当我创建 2 个列表时,如果我执行 a.intersect( b ) 和 b.intersect( a ):

def list1 = ["hello", "world", "world"];
def list2 = ["world", "world", "world"];

println( "Intersect list1 with list2: " + list1.intersect( list2 ) );
println( "Intersect list2 with list1: " + list2.intersect( list1) );

痕迹:(

Intersect list1 with list2: [world, world, world]
Intersect list2 with list1: [world, world]

您可以在此处复制它: http://groovyconsole.appspot.com/ 如果你想测试它)

如果数组都包含唯一元素,那么它会正常工作。一旦开始添加重复项,事情就会变得很奇怪:

def list1 = ["hello", "world", "test", "test"];
def list2 = ["world", "world", "world", "test"];

println( "Intersect list1 with list2: " + list1.intersect( list2 ) );
println( "Intersect list2 with list1: " + list2.intersect( list1 ) );

痕迹:

Intersect list1 with list2: [world, world, world, test]
Intersect list2 with list1: [world, test, test]

我认为 intersect() 的全部目的是为您提供公共元素,因此您将它们放入哪个顺序并不重要?

如果不是这种情况,我怎样才能只获取公共元素(预计数组中存在重复项)。例如,示例一应返回 ["world", "world"] ,示例二应返回 ["world", "test"]

编辑

为了澄清一点,这段代码应该测试用户数据是否仍然相同(假设它们在某些事情中间断开连接,并且我们希望确保数据没有被篡改,或者处于与以前相同的状态)。

无法保证列表的顺序(用户可以对其重新排序,但从技术上讲它仍然是“相同的”),并且可能会出现重复。

因此,类似: ["one", "one", "two"] 应该匹配 ["two", "one", "one"],而任何添加到列表中,或者数据的更改不应匹配。

Why in Groovy, when I create 2 lists, is there a difference if I do a.intersect( b ) and b.intersect( a ):

def list1 = ["hello", "world", "world"];
def list2 = ["world", "world", "world"];

println( "Intersect list1 with list2: " + list1.intersect( list2 ) );
println( "Intersect list2 with list1: " + list2.intersect( list1) );

traces:

Intersect list1 with list2: [world, world, world]
Intersect list2 with list1: [world, world]

(you can copy it here: http://groovyconsole.appspot.com/ if you want to test it)

If the arrays all contain unique elements, then it works as normal. Once you begin to add duplicates, it gets weird:

def list1 = ["hello", "world", "test", "test"];
def list2 = ["world", "world", "world", "test"];

println( "Intersect list1 with list2: " + list1.intersect( list2 ) );
println( "Intersect list2 with list1: " + list2.intersect( list1 ) );

traces:

Intersect list1 with list2: [world, world, world, test]
Intersect list2 with list1: [world, test, test]

I thought the whole point of intersect() was to give you the common elements, so it didn't matter which order you put them in?

If this isn't the case, how can I get only the common elements (expect duplicates in the array). E.g. example one should return ["world", "world"] and example two should return ["world", "test"]

Edit

To clarify a bit, this code should test that user data is still the same (assuming they disconnected in the middle of something and we want to make sure the data hasn't been tampered with, or is in the same state as before).

The order of the lists can't be guaranteed (the user could reorder it, but it's still technically the "same"), and duplicates are possible.

So something like: ["one", "one", "two"] should match ["two", "one", "one"], whereas any addition to the lists, or change in data shouldn't match.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ペ泪落弦音 2024-12-11 04:01:24

如果你看Collection.intersect的源码,可以看到该方法的逻辑遵循以下流程:

对于两个集合,leftright

  1. 如果 left 小于 right,则交换 leftright
  2. 添加所有 < code>left 进入集合(删除重复项)
  3. 对于每个right 中的元素如果存在于 leftSet 中,则将其添加到结果中

因此,对于最后 2 个示例;

def array1 = ["hello", "world", "test", "test"]
def array2 = ["world", "world", "world", "test"]

array1.intersect( array2 ) 会给出(如果我们在 Groovy 中编写相同的算法):

leftSet = new TreeSet( array1 ) // both same size, so no swap
// leftSet = [ 'hello', 'world', 'test' ]
right   = array2
result = right.findAll { e -> leftSet.contains( e ) }

其中(如果运行它),您可以看到意味着结果的值为 [world, world,世界,测试](正如您所发现的)。这是因为 right 中的每个元素都可以在 leftSet 中找到

不确定为什么第一个示例应返回 ["world","world"] 虽然...

稍后...

所以,我认为您正在寻找的是这样的:

def array1 = ["hello", "world", "test", "test"]
def array2 = ["world", "world", "world", "test"]
def intersect1 = array1.intersect( array2 ) as TreeSet
def intersect2 = array2.intersect( array1 ) as TreeSet
assert intersect1 == intersect2

为了处理集合中的重复项,就像 intersect1intersect2 将等于

[test, world]

稍后

我相信这会做什么你想要:

[array1,array2]*.groupBy{it}.with { a, b -> assert a == b }

If you look at the source for Collection.intersect, you can see that the logic of the method follows this flow:

for two collections, left and right

  1. Swap left and right if left is smaller than right
  2. Add all of left into a Set (removes duplicates)
  3. For each element in right if it exists in the leftSet, then add it to the results

So, for your last 2 examples;

def array1 = ["hello", "world", "test", "test"]
def array2 = ["world", "world", "world", "test"]

array1.intersect( array2 ) would give (if we wrote that same algorithm in Groovy):

leftSet = new TreeSet( array1 ) // both same size, so no swap
// leftSet = [ 'hello', 'world', 'test' ]
right   = array2
result = right.findAll { e -> leftSet.contains( e ) }

Which (if you run it), you can see means result has the value [world, world, world, test] (as you found). This is because every element in right can be found in the leftSet

Not sure why the first example should return ["world","world"] though...

later...

So, what I think you are looking for would be something like this:

def array1 = ["hello", "world", "test", "test"]
def array2 = ["world", "world", "world", "test"]
def intersect1 = array1.intersect( array2 ) as TreeSet
def intersect2 = array2.intersect( array1 ) as TreeSet
assert intersect1 == intersect2

in order that you cope with the duplicates in the collections, as then both intersect1 and intersect2 will be equal to

[test, world]

later still

I believe this does what you want:

[array1,array2]*.groupBy{it}.with { a, b -> assert a == b }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文