使用Java 8 Streams基于常见条件从两个不同的列表创建映射

Rav*_*avi 10 java java-8 java-stream

我有两个这样的列表实例:

List<NameAndAge> nameAndAgeList = new ArrayList<>();
nameAndAgeList.add(new NameAndAge("John", "28"));
nameAndAgeList.add(new NameAndAge("Paul", "30"));
nameAndAgeList.add(new NameAndAge("Adam", "31"));

List<NameAndSalary> nameAndSalaryList = new ArrayList<>();
nameAndSalaryList.add(new NameAndSalary("John", 1000));
nameAndSalaryList.add(new NameAndSalary("Paul", 1100));
nameAndSalaryList.add(new NameAndSalary("Adam", 1200));
Run Code Online (Sandbox Code Playgroud)

这里NameAndAge

class NameAndAge {
    public String name;
    public String age;

    public NameAndAge(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且NameAndSalary

private class NameAndSalary {
    private String name;
    private double salary;

    public NameAndSalary(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return name + ": " + salary;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想创建一个映射,其中key作为NameAndAge第一个列表中的对象,而值是NameAndSalary从第二个列表中创建的,其中两个对象中的名称相同.

所以,当我打印地图时,它应该如下所示:

{John: 28=John: 1000.0}
{Paul: 30=Paul: 1100.0}
{Adam: 31=Adam: 1200.0}
Run Code Online (Sandbox Code Playgroud)

我已经尝试过这样做了,但是结束返回类型是'无效'所以我无所畏惧,因为我是Streams的新手.

nameAndAgeList
    .forEach(n ->
        nameAndSalaryList
            .stream()
            .filter(ns -> ns.name.equals(n.name))
            .collect(Collectors.toList()));
Run Code Online (Sandbox Code Playgroud)

有人可以建议如何使用Java Streams API实现这一目标吗?

Era*_*ran 9

首先,假设您要创建一个HashMap,您的密钥类(NameAndAge)必须覆盖equalshashCode().

其次,为了提高效率,我建议你先从Map<String,NameAndSalary>第二个创建一个List:

Map<String,NameAndSalary> helper =
    nameAndSalaryList.stream()
                     .collect(Collectors.toMap(NameAndSalary::getName,
                                               Function.identity()));
Run Code Online (Sandbox Code Playgroud)

最后,您可以创建Map您想要的:

Map<NameAndAge,NameAndSalary> output = 
    nameAndAgeList.stream()
                  .collect(Collectors.toMap(Function.identity(),
                                            naa->helper.get(naa.getName())));
Run Code Online (Sandbox Code Playgroud)

  • 我正在写一个类似的答案.必须在不增加额外复杂性的情况下做出其他假设:(1)名称是唯一的,(2)给定名称应始终出现在两个列表中的对象中. (2认同)

Mat*_*att 1

这也应该能解决问题:

Map<NameAndAge, NameAndSalary> map = new HashMap<>();
nameAndAgeList.forEach(age -> {
     NameAndSalary salary = nameAndSalaryList.stream().filter(
              s -> age.getName().equals(s.getName())).
              findFirst().
              orElseThrow(IllegalStateException::new);
      map.put(age, salary);
});
Run Code Online (Sandbox Code Playgroud)

请注意,IllegalStateException如果找不到匹配的名称,它会抛出异常。