如何合并两个流并返回不同类型的列表?

时间:2017-04-21 03:27:24

标签: java-8 java-stream

我有两个流,我想将它们组合成不同的列表 即我有hashmap

Map<String, List<String>> citiesByZip = new HashMap<>();
保存此数据的

Alameda [95246, 95247]
Colusa [95987]

人员名单

  class Person {
    private String firstName;
    private String lastName;
    private int income;
    private int zipCode;



 People(String firstName, String lastName, int income, int zipCode) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.income = income;
        this.zipCode = zipCode;
    }

    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public int getIncome() {
        return income;
    }
    public int getZipCode() {
        return zipCode;
    }
}
 List<Person> persons= new ArrayList<>();

保存此数据

Junior Jane 20000 95246
Junior Jane 30000 95246
Joseph James 50000 95247
Patricia Allen 60000 95247
Opal Campbell 70000 95987
Dorothy Rook 80004 95987
Mary Nelson 80000 23666

我想将列表中的每个人映射到县的哈希映射,以找出哪个县居民

List <FinalObject> finalObjects= new  ArrayList<>();
finalObjects = Stream.concat(peopleStream.stream(), citiesByZip.entrySet().stream())
                .collect(Collectors.toMap(
                ))

此列表应返回最终对象列表 像这样

Junior Jane 20000 Alameda
Junior Jane 30000 Alameda
Joseph James 50000 Alameda
           .
           .
           etc

我知道我可以在传统循环的Java 7中完成这项工作,但我想知道我是否可以使用stream and lambda

在java 8中做同样的事情

1 个答案:

答案 0 :(得分:6)

首先,您需要一个数据结构来有效查找特定邮政编码,因为Map<String, List<String>>不适合。您可以将其转换为

Map<Integer,String> zipToCity = citiesByZip.entrySet().stream()
    .flatMap(e -> e.getValue().stream().map(Integer::valueOf)
                   .map(zip -> new AbstractMap.SimpleEntry<>(zip, e.getKey())))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

或者,您可以使用

Map<Integer,String> zipToCity = citiesByZip.entrySet().stream()
    .collect(HashMap::new,
            (m,e) -> e.getValue().forEach(zip -> m.put(Integer.valueOf(zip), e.getKey())),
            Map::putAll);

不需要临时AbstractMap.SimpleEntry实例,但看起来很像传统的迭代解决方案。事实上,对于顺序用例,循环实际上更简单。

然后,您可以使用单个流操作将Person实例转换为FinalObject个实例。由于您没有指定FinalObject类,我假设

class FinalObject {
    private String firstName, lastName, city;
    private int income;
    FinalObject(String firstName, String lastName, int income, String city) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.income = income;
        this.city = city;
    }

    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public int getIncome() {
        return income;
    }
    public String getCity() {
        return city;
    }
    @Override public String toString() {
        return firstName+" "+lastName+" "+income+" "+city;
    }
}

使用此定义,您可以使用zip查找进行转换,例如

List<FinalObject> finalObjects = persons.stream()
    .map(p -> new FinalObject(p.getFirstName(), p.getLastName(),
                  p.getIncome(), zipToCity.getOrDefault(p.getZipCode(), "Unknown")))
    .collect(Collectors.toList());

但是,使用委托代替可能是有益的:

class FinalObject {
    private Person p;
    String city;

    FinalObject(Person p, String city) {
        this.p = p;
        this.city = city;
    }

    public String getFirstName() {
        return p.getFirstName();
    }
    public String getLastName() {
        return p.getLastName();
    }
    public int getIncome() {
        return p.getIncome();
    }
    public String getCity() {
        return city;
    }
    @Override public String toString() {
        return getFirstName()+" "+getLastName()+" "+getIncome()+" "+city;
    }
}

List<FinalObject> finalObjects = persons.stream()
    .map(p -> new FinalObject(p, zipToCity.getOrDefault(p.getZipCode(), "Unknown")))
    .collect(Collectors.toList());