Groovy: разница с a.пересечение(b) и b.пересечение (a)

почему в Groovy, когда я создаю 2 списка, есть разница,если я делаю.пересечение( b) и b.пересечение (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 ответов


если вы посмотрите на источник 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 }