简体   繁体   English

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

[英]Create a map from two different lists based on common conditions using Java 8 Streams

I have two list instances like this: 我有两个这样的列表实例:

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

where NameAndAge is 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;
    }
}

and NameAndSalary is 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;
    }
}

Now, I want to create a map with key as NameAndAge object from the first list and value as NameAndSalary from the second list where the name is equal in both the objects. 现在,我想从第一个列表中创建一个带有键作为NameAndAge对象的映射,并从第二个列表中创建名称为NameAndSalary值,其中两个对象中的名称相等。

So, when I print the map, it should look like this: 所以,当我打印地图时,它应该如下所示:

{John: 28=John: 1000.0}
{Paul: 30=Paul: 1100.0}
{Adam: 31=Adam: 1200.0}

I have tried doing this, but the end return type is 'void' so I'm stuck clueless as I am new to Streams. 我已经尝试过这样做了,但是结束返回类型是'无效'所以我无所畏惧,因为我是Streams的新手。

nameAndAgeList
    .forEach(n ->
        nameAndSalaryList
            .stream()
            .filter(ns -> ns.name.equals(n.name))
            .collect(Collectors.toList()));

Can someone please advise how can this be achieved with Java Streams API? 有人可以建议如何使用Java Streams API实现这一目标吗?

First of all, assuming you are going to create a HashMap , your key class ( NameAndAge ) must override equals and hashCode() . 首先,假设您要创建HashMap ,您的密钥类( NameAndAge )必须覆盖equalshashCode()

Second of all, in order to be efficient, I suggest you first create a Map<String,NameAndSalary> from the second List : 其次,为了提高效率,我建议你先从第二个List创建一个Map<String,NameAndSalary>

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

Finally, you can create the Map you want: 最后,您可以创建所需的Map

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

This should do the trick, too: 这也应该可以解决问题:

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

Mind that it would throw an IllegalStateException if a matching name can't be found. 请注意,如果找不到匹配的名称,它将抛出IllegalStateException

This should work too 这应该也有效

List<String> commonNames = nameAndAgeList
    .stream()
    .filter(na -> 
         nameAndSalaryList.anyMatch((ns) -> ns.getName().equals(na.getName()))
    .collect(Collectors.toList());

Map<NameAndAge, NameAndSalary> map = 
    commonNames.stream().collect(Collectors.toMap(name -> 
        nameAndAgeList.get(name), name -> nameAndSalaryList.get(name)));

Without creating any intermediate object, without using a forEach , one liner: 没有创建任何中间对象,不使用forEach ,一个衬垫:

Map<NameAndAge, NameAndSalary> resultMap1 = nameAndAgeList.stream()
            .map(nameAndAge -> nameAndSalaryList.stream()
                    .filter(nameAndSalary -> nameAndAge.getName().equals(nameAndSalary.getName()))
                    .map(nameAndSalary -> new SimpleEntry<>(nameAndAge, nameAndSalary))
                    .collect(Collectors.toList()).get(0))
            .collect(Collectors.toMap(simpleEntry -> simpleEntry.getKey(), simpleEntry -> simpleEntry.getValue()));

You will have to add the getter functions to the domain classes though. 您必须将getter函数添加到域类中。 Accessing the properties directly might not be a good idea. 直接访问属性可能不是一个好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM