有条件地组合两套

时间:2017-12-09 09:58:09

标签: java java-8

我有一个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中有更简洁的方法吗?

4 个答案:

答案 0 :(得分:4)

set1.addAll(set2.stream().filter(e -> set1.stream()
                    .noneMatch(p -> p.getName().equals(e.getName())))
                    .collect(Collectors.toSet()));

答案 1 :(得分:1)

如果你有意义覆盖equalshashCode,你可以使用以下内容:

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

但请记住,只有在覆盖equalshashCode时才有可能解决此问题。  `

答案 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())));