![](/img/trans.png)
[英]How to filter objects contained in two Sets based on a single property without overriding equals() and hashCode()
[英]How to compare two Sets of objects Not overriding equals/hashCode with Comparator and Streams
我有两个Set
如下所示:
Set<Book> s1 = createBooks();
Set<Book> s2 = createBooks(); // or any set of values
这个方法:
private Set<Book> createBooks() {
List<String> name = Arrays.asList("book 1", "book 2", "book 3");
List<BookType> type = Arrays.asList(BookType.TYPEONE, BookType.TYPETWO);
Set<Book> listOfBooks = new HashSet<>();
for(int i=0; i<2; i++) {
Book book = new Book();
book.setName(name.get(i));
book.setType(type.get(i));
listOfBooks.add(books);
}
return listOfBooks;
}
还有这个 class:
Class Book {
private String name;
private BookType type;
//here is getter and setter ...
}
我确实实现了这个Comparator
,但我不确定它是否正常工作:
Comparator<Book> comparingBooks = (o1, o2) -> {
if (o1.getName().compareTo(o2.getName()) == 0) {
return o1.getType().compareTo(o2.getType());
}
return o1.getName().compareTo(o2.getName());
};
//I did try this implementation but am not sure it's working as well:
//Comparator<Book> comparingBooks = Comparator.comparing((Book b)->b.getNName())
.thenComparing(b->b.getType());
预期结果为true
时的集合示例:
s1 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.TWO));
s2 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.TWO));
预期结果为false
时的集合示例:
s1 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.TWO));
s2 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.ONE));
我需要将这些集合与以下内容进行比较:
// this flag should validate any difference of Name
// and Type by returning true,
// if both Sets have exactly the same objects,
// it should return false.
boolean compareBooks = s1.stream().anyMatch(a -> s2.stream().anyMatch(b -> comparingBooks.compare(a, b) != 0));
我也试过这个但是没有用并且总是返回相同的值:
boolean compareBooks = SetUtils.isEqualSet(s1, s2);
我没有 equals 和 hashcode 实现,也无法实现它。
java 8 和比较器还有其他方法可以检查和比较这些集合吗?
为了在这种情况下创建Comparator
,您需要显式提供通用类型信息,例如: <Book, String>comparing()
,其中Book
和String
是Comparator.comparing()
的参数类型和返回类型Function
期望作为参数。
如果没有显式声明,编译器没有足够的数据来确定变量book
的类型,在comparing()
和thenComparing()
中,它的类型将被推断为Object
。
Comparator<Book> comparingBooks =
Comparator.<Book, String>comparing(book -> book.getName())
.thenComparing(book -> book.getType());
如果仅使用 static 方法之一,编译器将根据语言环境变量Comparator<Book> comparingBooks
的类型将book
变量的类型正确推断为Book
。
两个方法 lambda 表达式都可以用方法引用替换:
Comparator<Book> comparingBooks =
Comparator.<Book, String>comparing(Book::getName)
.thenComparing(Book::getType);
有关如何使用 Java 8 种方法构建比较器的更多信息,请查看本教程
应通过返回 true 来验证 Name 和 Type 的任何差异,如果两个 Set 具有完全相同的对象,则应返回 false。
Stream s1.stream().anyMatch(a -> s2.stream().anyMatch(b ->...))
当前正在检查第一个集合s1
中是否有一个元素不同于 s2 中的任何元素. 即嵌套的anyMatch()
将为在s1中遇到的第一个元素返回true
,而在s2中没有匹配的元素。 在将Book("book 1", BookType.ONE)
( s1 ) 与Book("book 2", BookType.TWO)
( s2 ) 进行比较后, anyMatch()
通过返回true
终止。 并附anyMatch()
操作传播这个结果。
第二个例子也会发生同样的情况。 同一对元素不同,虽然你换了一个类型,名字却不一样。 结果是true
。
笔记:
Book
(不是Books )、 Event
、 Person
等。equals/hashCode
合同,您的要求非常不寻常。 您可以使用比较器创建一个TreeSet
来实现相等性而不是equals()
:
Set<Books> listOfBooks = new TreeSet<>(comparingBooks);
现在您可以使用标准的集合方法来比较集合:
boolean compareBooks = !Collections.disjoint(s1, s2);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.