Java 8流 - 合并两个集合,使其在特定字段中保持唯一

时间:2018-01-08 14:57:27

标签: java java-8 java-stream

我有两个狗列表 - dogsList1,dogsList2
我想创建一个具有唯一名称字段的所有狗的列表 (意思是,如果我遇到第二只同名的狗,我不会将它添加到结果列表中)

这是我在java中可以做的最好的,但是它收集了唯一的名称,而不是Dogs:
(狗包含除名称之外的其他字段)

// collect all dogs names from first list
List<String> dogNames1 = dogsList1.stream()
     .map(x -> x.getName()).collect(Collectors.toList()); 

dogList2.stream()
     .filter(x->!dogNames1.contains(x.getName()))
     .forEach( x->
            dogsList1.add(x);
     );

可以改进吗?还有其他更好的解决方案或优化的方法吗?

2 个答案:

答案 0 :(得分:6)

您可以使用合并多个流并删除重复项。

对于给定名字的第一只狗,你可以做

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class A {

    public static void main(String[] args) {
        List<Dog> dogList1 = Arrays.asList(new Dog("a", 1), new Dog("b", 2), new Dog("f", 3));
        List<Dog> dogList2 = Arrays.asList(new Dog("b", 4), new Dog("c", 5), new Dog("f", 6));
        List<Dog> dogList3 = Arrays.asList(new Dog("b", 7), new Dog("d", 8), new Dog("e", 9));
        List<Dog> dogs = new ArrayList<>(
                Stream.of(dogList1, dogList2, dogList3)
                        .flatMap(List::stream)
                        .collect(Collectors.toMap(Dog::getName,
                                d -> d,
                                (Dog x, Dog y) -> x == null ? y : x))
                        .values());
        dogs.forEach(System.out::println);
    }
}

class Dog {
    String name;
    int id;

    public Dog(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}

打印

Dog{name='a', id=1}
Dog{name='b', id=2}
Dog{name='c', id=5}
Dog{name='d', id=8}
Dog{name='e', id=9}
Dog{name='f', id=3}

在每种情况下,您都可以看到保留名称的第一个实例。

对于唯一名称

Set<String> names = Stream.of(dogList1, dogList2, dogList3)
                          .flatMap(List::stream)
                          .map(Dog::getName)
                          .collect(Collectors.toSet());

答案 1 :(得分:2)

这可能是一个选项

  List<String> dogNames = Stream.concat(dogsList1.stream(),dogsList2.stream())
                          .map(x -> x.getName())
                          .distinct()
                          .collect(Collectors.toList());