Groovy: разница с a.intersect (b) и b.intersect (a) - PullRequest
7 голосов
/ 12 сентября 2011

Почему в 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"], тогда как любое добавление к спискам или изменение данных не должны совпадать.

1 Ответ

9 голосов
/ 12 сентября 2011

Если вы посмотрите на источник Collection.intersect, вы увидите, что логика метода соответствует этому потоку:

для двух коллекций, left и right

  1. Поменять left и right, если left меньше right
  2. Добавить все 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, world, test] (как вы нашли).Это связано с тем, что каждый элемент в 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

, чтобы вы справились с дубликатами в коллекциях, как тогда intersect1 и intersect2будет равен

[test, world]

позже еще

Я считаю, что это делает то, что вы хотите:

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