我有一个名为FormObject的对象,它包含两个ArrayLists - oldBooks和newBooks - 两者都包含Book对象。
允许oldBooks包含重复的Book对象 newBooks不允许在其自身中包含重复的Book对象,也不能在oldBooks列表中包含任何Book对象的副本。
重复Book的定义很复杂,我无法覆盖equals方法,因为定义在Book对象的所有用途中都不是通用的。
我打算在FormObject类上有一个名为removeDuplicateNewBooks的方法,它将执行上述功能。
你将如何实现这一目标?我的第一个想法是使用HashSets来消除重复但不能在Book对象上覆盖equals意味着它不起作用。
答案 0 :(得分:7)
您可以将TreeSet
与自定义Comparator<Book>
:
TreeSet
,Comparator
实现您想要的自定义逻辑set.addAll(bookList)
现在Set
只包含独特的图书。
答案 1 :(得分:4)
使新书独一无二:
围绕Book创建一个包装类,并根据附带的book对象声明它的equals / hashCode方法:
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()
};
}
}
修改强> 优化了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类本身)
修改强> (删除了对apache commons的引用,因为我改进的equals / hashCode方法更好)
答案 2 :(得分:1)
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的提交者。