Имею два ArrayList
типа Answer
(самодельный класс).
Я хотел бы сравнить два списка, чтобы увидеть, содержат ли они одинаковое содержимое, но без учета порядка.
Пример:
//These should be equal.
ArrayList<String> listA = {"a", "b", "c"}
ArrayList<String> listB = {"b", "c", "a"}
List.equals
заявляет, что два списка равны, если они содержат одинаковый размер, содержимое и порядок элементов. Я хочу то же самое, но без всякого порядка.
Есть простой способ сделать это? Или мне нужно будет выполнить вложенный цикл for и вручную проверить каждый индекс обоих списков?
Примечание: я не могу изменить их ArrayList
на список другого типа, они должны оставаться такими.
Ответы:
Вы можете отсортировать оба списка, используя,
Collections.sort()
а затем использовать метод equals. Немного лучшее решение - сначала проверить, имеют ли они одинаковую длину, перед заказом, если нет, то они не равны, затем отсортировать, а затем использовать равные. Например, если у вас есть два списка строк, это будет примерно так:источник
Collections.sort
происходит) - т.е. передавать копию.one = new ArrayList<String>(one); two = new ArrayList<String>(two);
чтобы не испортить аргументы.if(one == null || two == null || one.size() != two.size()){ return false; }
как вы уже проверяете, равны ли один и два значения nullВероятно, самый простой способ составить любой список:
источник
[a, b, c]
и[c, b, a, b]
имеют одинаковое содержимое. В этом ответе говорится, что они есть, но может быть, что для OP они этого не делают (поскольку один содержит дубликат, а другой нет). Не говоря уже о вопросах эффективности.Коллекции Apache Commons снова приходят на помощь:
Docs:
источник
false
? Смотрите мой ответ.implementation 'org.apache.commons:commons-collections4:4.3'
оставил мнеCaused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process
путь к ошибке .источник
count
станет отрицательным, что упростит тело цикла до.if(!counts.containsKey(item) || --counts.get(item).count < 0) return false;
Кроме того, 3-й цикл можно упростить доfor(Count c: counts.values()) if(c.count != 0) return false;
counts
является ли пустым»), но не хотел скрывать главный момент: использование карты в основном превращает это в проблему O (N + M) и является самым большим преимуществом, которое вы, вероятно, получите.Map.merge
поскольку в большинстве случаев использование целых чисел в коробке может быть проще и эффективнее. См. Также этот ответ …Я бы сказал, что эти ответы упускают один трюк.
Блох в своей замечательной и краткой « Эффективной Java» в пункте 47, озаглавленном «Знайте и используйте библиотеки», говорит: «Подводя итог, не изобретайте велосипед». И он приводит несколько очень понятных причин, почему нет.
Здесь есть несколько ответов, которые предлагают методы из
CollectionUtils
библиотеки Apache Commons Collections, но ни один из них не нашел наиболее красивого и элегантного способа ответа на этот вопрос :Виновники : то есть элементы, которые не являются общими для обоих
Lists
. Определить, к каким виновным относятся,list1
а какие кlist2
, относительно просто использоватьCollectionUtils.intersection( list1, culprits )
иCollectionUtils.intersection( list2, culprits )
.Однако он имеет тенденцию разваливаться в таких случаях, как {"a", "a", "b"}
disjunction
с {"a", "b", "b"} ... за исключением того, что это не сбой программного обеспечения, а присущие природе тонкости / неоднозначности желаемой задачи.Вы всегда можете проверить исходный код (l. 287) для подобной задачи, созданный инженерами Apache. Одно из преимуществ использования их кода состоит в том, что он будет тщательно опробован и протестирован, с ожидаемыми и устраненными множеством крайних случаев и ошибок. Вы можете скопировать и настроить этот код по своему усмотрению, если потребуется.
NB. Сначала я был разочарован тем, что ни один из
CollectionUtils
методов не предоставляет перегруженную версию, позволяющую вам навязывать свою собственнуюComparator
(чтобы вы могли переопределитьequals
в соответствии со своими целями).Но из collections4 4.0 появился новый класс,
Equator
который «определяет равенство между объектами типа T». При изучении исходного кода collections4 CollectionUtils.java они, похоже, используют это с некоторыми методами, но, насколько я могу понять, это не применимо к методам в верхней части файла, использующимCardinalityHelper
класс ... который включитьdisjunction
иintersection
.Я предполагаю , что люди , Apache не удосужились это еще и потому , что это нетривиально: вы должны создать что - то вроде класса «AbstractEquatingCollection», который вместо того , чтобы использовать присущие его элементы
equals
иhashCode
методы вместо этого должен использовать те ofEquator
для всех основных методов, таких какadd
,contains
и т. д. NB на самом деле, когда вы смотрите на исходный код,AbstractCollection
не реализует и не реализуетadd
свои абстрактные подклассы, такие какAbstractSet
..., вам нужно дождаться, пока конкретные классы, такие какHashSet
иArrayList
доadd
реализовано. Довольно головная боль.А пока, полагаю, понаблюдайте за этим пространством. Очевидным промежуточным решением было бы обернуть все ваши элементы в специальный класс-оболочку, который использует
equals
иhashCode
реализует тот вид равенства, который вы хотите ... затем манипулируйтеCollections
этими объектами-оболочками.источник
Если количество элементов не имеет значения (что означает: повторяющиеся элементы рассматриваются как один), то есть способ сделать это без сортировки:
boolean result = new HashSet<>(listA).equals(new HashSet<>(listB));
Это позволит создать
Set
из каждогоList
, а затем использоватьHashSet
«sequals
метод , который (конечно) пренебрегает заказа.Если количество элементов имеет значение, вы должны ограничиться возможностями, предоставляемыми
List
; Ответ @jschoen в этом случае был бы более подходящим.источник
Преобразование списков для гуавы в MultiSet работает очень хорошо. Они сравниваются независимо от их порядка, а также учитываются повторяющиеся элементы.
источник
Это основано на решении @cHao. Я внес несколько исправлений и улучшений производительности. Это работает примерно в два раза быстрее, чем решение с равным порядком копий. Подходит для любого типа коллекции. Пустые коллекции и null считаются равными. Используйте в своих интересах;)
источник
false
когда ключ не существует или его счетчик становится отрицательным. Поскольку общий размер обоих списков совпадает (это было проверено заранее), невозможно иметь ненулевые значения после второго цикла, так как не может быть положительных значений для ключа без отрицательных значений для другого ключа.Подумайте, как бы вы сделали это сами, не имея компьютера или языка программирования. Я даю вам два списка элементов, и вы должны сказать мне, содержат ли они одинаковые элементы. Как бы ты это сделал?
Один из подходов, как упоминалось выше, состоит в том, чтобы отсортировать списки, а затем переходить от одного элемента к другому, чтобы проверить, равны ли они (что и
List.equals
происходит). Это означает, что либо вам разрешено изменять списки, либо вам разрешено их копировать - и, не зная назначения, я не могу знать, разрешено ли одно или оба из них.Другой подход - просмотреть каждый список, подсчитывая, сколько раз появляется каждый элемент. Если оба списка имеют одинаковое количество в конце, они имеют одинаковые элементы. Код для этого должен был бы преобразовать каждый список в карту,
elem -> (# of times the elem appears in the list)
а затем вызватьequals
две карты. Если карты естьHashMap
, каждый из этих переводов является операцией O (N), как и сравнение. Это даст вам довольно эффективный с точки зрения времени алгоритм за счет дополнительной памяти.источник
У меня была такая же проблема, и я придумал другое решение. Этот также работает, когда задействованы дубликаты:
Преимущества по сравнению с некоторыми другими решениями:
[1,2,3,3]
и другой массив,[1,2,2,3]
большинство решений здесь говорят вам, что они одинаковы, если не учитывать порядок. Это решение позволяет избежать этого, удаляя одинаковые элементы из временных списков;equals
), а не ссылочное равенство (==
);implement Comparable
), чтобы это решение работало.источник
Если вы не надеетесь сортировать коллекции и вам нужен результат, который ["A" "B" "C"] не равен ["B" "B" "A" "C"],
недостаточно, возможно, вам также нужно проверить размер:
источник
Решение, использующее метод вычитания CollectionUtils:
источник
Если вам важен порядок, просто используйте метод equals:
Если вас не волнует порядок, используйте это
источник
Лучшее из обоих миров [@DiddiZ, @Chalkos]: этот в основном основан на методе @Chalkos, но исправляет ошибку (ifst.next ()) и улучшает начальные проверки (взятые из @DiddiZ), а также устраняет необходимость скопируйте первую коллекцию (просто удаляет элементы из копии второй коллекции).
Не требуя функции хеширования или сортировки и позволяя раннее существование при неравенстве, это наиболее эффективная реализация. Это если у вас нет длины коллекции в тысячи или более и очень простой функции хеширования.
источник
Это альтернативный способ проверить равенство списков массивов, которые могут содержать нулевые значения:
источник
Мое решение для этого. Это не так круто, но работает хорошо.
источник
В этом случае списки {"a", "b"} и {"b", "a"} равны. И {"a", "b"} и {"b", "a", "c"} не равны. Если вы используете список сложных объектов, не забудьте переопределить метод equals , так как containsAll использует его внутри.
источник
AbstractCollection.containsAll()
. Вы должны позволить иметь повторяющиеся элементы, о которых мы говоримLists
, а не оSets
. Пожалуйста, посмотрите мой ответ.