Comparing two lists and removing duplicates from one

℡╲_俬逩灬. 提交于 2019-12-01 07:36:41

You can use a TreeSet with a custom Comparator<Book>:

  • construct the TreeSet with a Comparator implementing the custom logic you want
  • use set.addAll(bookList)

Now the Set contains only unique books.

For making the new books unique:

Create a wrapper class around Book and declare it's equals / hashCode methods based on the enclosed book object:

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: Optimized equals and hashCode and fixed a bug in hashCode.

Now use a set to remove duplicates:

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());
}

(But of course the TreeSet answer with the custom comparator is more elegant because you can use the Book class itself)

EDIT: (removed reference to apache commons because my improved equals / hashCode methods are better)

HashingStrategy is the concept you're looking for. It's a strategy interface that allows you to define custom implementations of equals and hashcode.

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

Eclipse Collections includes hash tables as well as iteration patterns based on hashing strategies. First, you'd create your own HashingStrategy to answer whether two Books are equal.

Next, you'd use distinct() to remove duplicates within newBooks and a UnifiedSetWithHashingStrategy to eliminate duplicates across the lists.

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);

The distinct() method returns only the unique items according to the hashing strategy. It returns a list, not a set, preserving the original order. The call to reject() returns another new list without the elements that the set contains, according to the same hashing strategy.

If you can change newBooks to implement an Eclipse Collections interface, then you can call the distinct() method directly.

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

Note: I am a committer for Eclipse Collections.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!