Перекрестное сравнение элементов ArrayList и удаление дубликатов - PullRequest
3 голосов
/ 17 января 2012

У меня есть ArrayList<MyObject>, который может (или не может) содержать дубликаты MyObject, которые мне нужно удалить из списка.Как я могу сделать это так, чтобы мне не приходилось проверять дублирование дважды, как если бы я повторял список в двух циклах for и перепроверял каждый элемент с каждым другим элементом.

Мне просто нужно проверить каждый элемент один раз, поэтому достаточно сравнить A:B - я не хочу снова сравнивать B:A, как я уже это сделал.

Более того;можно просто удалить дубликаты из списка во время цикла ?Или это каким-то образом нарушит список и мой цикл?

Редактировать: Хорошо, я забыл важную часть, просматривая первые ответы: дубликат из MyObject подразумевается не только вJava означает Object.equals (Object) , но мне нужно иметь возможность сравнивать объекты, используя мой собственный алгоритм, поскольку равенство MyObject s вычисляется с использованием алгоритма, который проверяет поля объекта вособый способ, который мне нужно реализовать!

Кроме того, я не могу просто переопределить euqals в MyObject, так как есть несколько разных алгоритмов, которые реализуют разные стратегии для проверки равенства двух MyObject s- например, существует простой HashComparer и более сложный EuclidDistanceComparer, причем оба AbstractComparers реализуют различные алгоритмы для public abstract boolean isEqual(MyObject obj1, MyObject obj2);

Ответы [ 5 ]

4 голосов
/ 17 января 2012

Создайте набор, и он автоматически удалит дубликаты, если порядок не важен.

Set<MyObject> mySet = new HashSet<MyObject>(yourList);
4 голосов
/ 17 января 2012

Сортируйте список, и дубликаты будут соседствовать друг с другом, что облегчает их идентификацию и удаление.Просто просмотрите список, помня значение предыдущего элемента, чтобы вы могли сравнить его с текущим.Если они одинаковы, удалите текущий элемент.

И если вы используете обычный for -петл для просмотра списка, вы контролируете текущую позицию.Это означает, что когда вы удаляете элемент, вы можете уменьшить позицию (n--), чтобы в следующий раз вокруг цикла посещать ту же позицию (которая теперь будет следующим элементом).

Вам нужнопредоставить пользовательское сравнение в вашем роде?Это не так сложно:

Collections.sort(myArrayList, new Comparator<MyObject>() {

    public int compare(MyObject o1, MyObject o2) {
        return o1.getThing().compareTo(o2.getThing());
    }
});

Я написал этот пример так, что getThing().compareTo() заменяет все, что вы хотите сделать, чтобы сравнить два объекта.Вы должны вернуть целое число, равное нулю, если они одинаковы, больше 1, если o1 больше, чем o2, и -1, если o1 меньше, чем o2.Если бы getThing() вернул String или Date, все было бы в порядке, потому что у этих классов уже есть метод compareTo.Но вы можете поместить любой код, который вам нужен, в ваш пользовательский Comparator.

2 голосов
/ 17 января 2012

Создание новой коллекции на основе набора HashSet. Не забудьте реализовать equals и хэш-код для MyObject.

Удачи!

1 голос
/ 17 января 2012

Если порядок объектов незначителен

Если порядок не важен, вы можете поместить элементы списка в Set:

Set<MyObject> mySet = new HashSet<MyObject>(yourList);

Дубликаты будут удалены автоматически.

Если порядок объектов значителен

Если порядок значим, вы можете вручную проверить наличие дубликатов, например, используя этот фрагмент:

// Copy the list.
ArrayList<String> newList = (ArrayList<String>) list.clone();

// Iterate
for (int i = 0; i < list.size(); i++) {
    for (int j = list.size() - 1; j >= i; j--) {
        // If i is j, then it's the same object and don't need to be compared.
        if (i == j) {
            continue;
        }
        // If the compared objects are equal, remove them from the copy and break
        // to the next loop
        if (list.get(i).equals(list.get(j))) {
            newList.remove(list.get(i));
            break;
        }
        System.out.println("" + i + "," + j + ": " + list.get(i) + "-" + list.get(j));
    }
}

Это удалит все дубликатыоставляя последнее дублирующее значение как исходную запись.Кроме того, он будет проверять каждую комбинацию только один раз.

Использование Java 8

Java Streams делает его еще более элегантным:

List<Integer> newList = oldList.stream()
    .distinct()
    .collect(Collectors.toList());

Если вам нужно рассмотреть два изваши объекты равны на основании вашего собственного определения, вы можете сделать следующее:

public static <T, U> Predicate<T> distinctByProperty(Function<? super T, ?> propertyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(propertyExtractor.apply(t));
}

( Stuart Marks )

И тогда вы можете сделать это:

List<MyObject> newList = oldList.stream()
    .filter(distinctByProperty(t -> {
        // Your custom property to use when determining whether two objects
        // are equal. For example, consider two object equal if their name
        // starts with the same character.
        return t.getName().charAt(0);
    }))
    .collect(Collectors.toList());

Futhermore

Вы не можете изменять список, пока Iterator (который обычно используется в цикле for-each) просматривает массив.Это бросит ConcurrentModificationException.Вы можете изменить массив, если зацикливаете его, используя цикл for.Затем вы должны контролировать положение итератора (уменьшая его при удалении записи).

0 голосов
/ 17 января 2012

Или http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html, если вам нужен порядок сортировки ..

РЕДАКТИРОВАТЬ : как насчет производных от http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html,, это позволит вам передать вКомпаратор во время строительства.Вы переопределяете add(), чтобы использовать свой компаратор вместо equals() - это даст вам гибкость в создании различных наборов, упорядоченных в соответствии с вашим компаратором, и они будут реализовывать вашу стратегию "равенства".

Незабудь про equals() и hashCode() хотя ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...