Java 比较两个列表并从一个列表中删除重复项
我有一个名为FormObject的对象,它包含两个ArrayList——oldBooks和newBooks——它们都包含Book对象 允许旧图书包含重复的图书对象 newBooks本身不允许包含重复的图书对象,并且不能在oldBooks列表中包含任何图书对象的副本 重复图书的定义很复杂,我不能覆盖equals方法,因为该定义在图书对象的所有用途中都不是通用的 我计划在FormObject类上有一个名为RemovedUpplicateNewBooks的方法,它将执行上述功能 你将如何着手实施这一点?我的第一个想法是使用hashset来消除重复项,但不能覆盖Book对象上的equals意味着它将不起作用。您可以将a与自定义的Java 比较两个列表并从一个列表中删除重复项,java,collections,duplicates,equals,Java,Collections,Duplicates,Equals,我有一个名为FormObject的对象,它包含两个ArrayList——oldBooks和newBooks——它们都包含Book对象 允许旧图书包含重复的图书对象 newBooks本身不允许包含重复的图书对象,并且不能在oldBooks列表中包含任何图书对象的副本 重复图书的定义很复杂,我不能覆盖equals方法,因为该定义在图书对象的所有用途中都不是通用的 我计划在FormObject类上有一个名为RemovedUpplicateNewBooks的方法,它将执行上述功能 你将如何着手实施这一点
比较器一起使用:
- 使用实现所需自定义逻辑的
比较器构建树集
- 使用
set.addAll(图书列表)
现在,集合
只包含唯一的书籍。要使新书具有唯一性:
围绕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中的一个bug
现在使用集合删除重复项:
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());
}
Set wrappers=new HashSet();
用于(书籍:新书){
添加(新的包装器(书);
}
newBooks.clear();
for(包装器:包装器){
add(wrapper.getBook());
}
(当然,带有自定义比较器的TreeSet答案更优雅,因为您可以使用Book类本身)
编辑:
(删除了对apache commons的引用,因为我改进的equals/hashCode方法更好)是您正在寻找的概念。它是一个策略接口,允许您定义equals和hashCode的自定义实现
public interface HashingStrategy<E>
{
int computeHashCode(E object);
boolean equals(E object1, E object2);
}
distinct()
方法根据散列策略只返回唯一的项。它返回一个列表,而不是一个集合,保留原始顺序。调用reject()
根据相同的散列策略返回另一个新列表,其中不包含集合包含的元素
如果您可以更改newBooks以实现Eclipse集合接口,那么您可以直接调用distinct()
方法
MutableList<Book> newBooks = ...;
MutableList<Book> result = newBooks.distinct(hashingStrategy).reject(oldBooks::contains);
MutableList新书=。。。;
MutableList result=newBooks.distinct(hashingStrategy).reject(oldBooks::contains);
注意:我是Eclipse Collections的提交者。那么,您如何检查图书是否相等?如果您知道确定重复的逻辑,那么您应该能够使用相同的逻辑覆盖equals方法。如果图书相等的定义不是通用的,您将如何通用地确定图书是否是重复的?这有什么不同将其重写等于,而不是以其他方式定义它?嗯,这是一个有趣的解决方案,绝对不是我会想到的。我考虑过这一点,但在语义上使用比较器是“错误的”,因为比较器应该用于对对象进行排序,而不是测试平等的替代定义。是的,但契约是正确的当且仅当对象相等时,比较器返回0,这意味着相等测试。是的,这是真的。这绝对是最优雅的解决方案。
MutableList<Book> newBooks = ...;
MutableList<Book> result = newBooks.distinct(hashingStrategy).reject(oldBooks::contains);