Сравнение двух списков и удаление дубликатов из одного - PullRequest
4 голосов
/ 30 августа 2010

У меня есть объект под названием FormObject, который содержит два ArrayLists - oldBooks и newBooks - каждый из которых содержит объекты Book.

oldBooks разрешено содержать дубликаты объектов Book. NewBooks запрещено содержать дубликаты объектов Book внутри себяи не может включать дубликаты объектов Book в список oldBooks.

Определение дубликата Book является сложным, и я не могу переопределить метод equals, поскольку определение не универсально для всех применений объекта Book.

Я планирую создать метод для класса FormObject с именем removeDuplicateNewBooks, который будет выполнять вышеуказанную функциональность.

Как вы будете реализовывать это?Моей первой мыслью было использование HashSets для устранения дубликатов, но невозможность переопределить равные для объекта Book означает, что он не будет работать.

Ответы [ 3 ]

7 голосов
/ 30 августа 2010

Вы можете использовать TreeSet с пользовательским Comparator<Book>:

  • создайте TreeSet с Comparator, реализующим нужную вам логику
  • использовать set.addAll(bookList)

Теперь Set содержит только уникальные книги.

4 голосов
/ 30 августа 2010

Для того, чтобы сделать новые книги уникальными:

Создайте класс-оболочку для Book и объявите его методы equals / hashCode на основе вложенного объекта book:

public class Wrapper{

    private final Book book;

    public Wrapper(final Book book){
        assert book != null;
        this.book = book;
    }

    public Book getBook(){
        return this.book;
    }

    @Override
    public boolean equals(final Object other){
        return other instanceof Wrapper ? 
            Arrays.equals(
                this.getBookInfo(),
                ((Wrapper) other).getBookInfo()
            ) : false;
    }

    @Override
    public int hashCode(){
        return Arrays.hashCode(this.getBookInfo());
    }

    private String[] getBookInfo(){
        return new String[] { 
            this.book.getAuthor(), 
            this.book.getTitle(), 
            this.book.getIsbn() 
        };
    }

}

EDIT: Оптимизирован equals и hashCode и исправлена ​​ошибка в hashCode.

Теперь используйте набор для удаления дубликатов:

Set<Wrapper> wrappers = new HashSet<Wrapper>();
for(Book book: newBooks){
    wrappers.add(new Wrapper(book);
}
newBooks.clear();
for(Wrapper wrapper: wrappers){
    newBooks.add(wrapper.getBook());
}

(Но, конечно, ответ TreeSet с пользовательским компаратором более элегантен, поскольку вы можете использовать сам класс Book)

EDIT: (удалена ссылка на Apache Commons, потому что мои улучшенные методы equals / hashCode лучше)

1 голос
/ 15 января 2016

HashingStrategy - это концепция, которую вы ищете.Это интерфейс стратегии, который позволяет вам определять пользовательские реализации equals и hashcode.

public interface HashingStrategy<E>
{
    int computeHashCode(E object);
    boolean equals(E object1, E object2);
}

Eclipse Collections включает в себя хеш-таблицы, а также шаблоны итераций на основе стратегий хеширования.Во-первых, вы должны создать свой собственный HashingStrategy, чтобы ответить, равны ли два Books.

Далее, вы будете использовать distinct() для удаления дубликатов в пределах newBooks и UnifiedSetWithHashingStrategy для устранениядублирует списки.

List<Book> oldBooks = ...;
List<Book> newBooks = ...;
HashingStrategy<Book> hashingStrategy = new HashingStrategy() { ... };
Set<Book> set = UnifiedSetWithHashingStrategy<>(hashingStrategy, oldBooks);
List<Book> result = ListIterate.distinct(newBooks, hashingStrategy).reject(set::contains);

Метод distinct() возвращает только уникальные элементы в соответствии со стратегией хеширования.Возвращает список, а не набор, сохраняя исходный порядок.Вызов reject() возвращает другой новый список без элементов, содержащихся в наборе, в соответствии с той же стратегией хеширования.

Если вы можете изменить newBooks для реализации интерфейса Eclipse Collections, то вы можете вызвать distinct() метод напрямую.

MutableList<Book> newBooks = ...;
MutableList<Book> result = newBooks.distinct(hashingStrategy).reject(oldBooks::contains);

Примечание: я являюсь коммиттером для Eclipse Collections.

...