我有一个Person对象,它有一个name属性和一些其他属性。我有两个带有Person对象的HashSet。请注意,name不是唯一属性,这意味着具有相同名称的两个人可以具有不同的高度,因此使用HashSet并不能保证两个具有相同名称的人不在同一个集合中。
我需要将一个集合添加到另一个集合,因此结果中没有具有相同名称的人员。所以像这样:
public void combine(HashSet<Person> set1, HashSet<Person> set2){
for (String item2 : set2) {
boolean exists = false;
for (String item1 : set1) {
if(item2.name.equals(item1.name)){
exists = true;
}
}
if(!exists){
set1.add(item2);
}
}
}
在java8中有更简洁的方法吗?
答案 0 :(得分:4)
set1.addAll(set2.stream().filter(e -> set1.stream()
.noneMatch(p -> p.getName().equals(e.getName())))
.collect(Collectors.toSet()));
答案 1 :(得分:1)
如果你有意义覆盖equals
和hashCode
,你可以使用以下内容:
Set<Parent> result = Stream.concat(set1.stream(), set2.stream())
.collect(Collectors.toSet());
如果没有Java 8流,您可以轻松地执行此操作:
Set<Parent> result = new HashSet<>();
result.addAll(set1);
result.addAll(set2);
但请记住,只有在覆盖equals
和hashCode
时才有可能解决此问题。
`
答案 2 :(得分:0)
您可以使用名称作为键的HashMap
,然后避免方法的O(n²)
运行时复杂性。如果你需要HashSet,那么没有更快的方法。即使您使用Java 8 Streams。它们增加了更多的开销。
public Map<String, Person> combine(Set<Person> set1, Set<Person> set2) {
Map<String, Person> persons = new HashMap<>();
set1.forEach(pers -> persons.computeIfAbsent(pers.getName(), key -> pers));
set2.forEach(pers -> persons.computeIfAbsent(pers.getName(), key -> pers));
return persons;
}
答案 3 :(得分:0)
或者,您可以创建自己的收藏家。假设你确定两个同名的人实际上是同一个人:
首先,您可以定义收集器:
static Collector<Person, ?, Map<String, Person>> groupByName() {
return Collector.of(
HashMap::new,
(a,b) -> a.putIfAbsent(b.name, b),
(a,b) -> { a.putAll(b); return a;}
);
}
然后您可以使用它按名称对人员进行分组:
Stream.concat(s1.stream(), s2.stream())
.collect(groupByName());
但是,这会给你一个Map<String, Person>
而你只想找到整套人员,对吗?
所以,你可以这样做:
Set<Person> p = Stream.concat(s1.stream(), s2.stream())
.collect(collectingAndThen(groupByName(), p -> new HashSet<>(p.values())));