处理Collectors.toMap()函数中的重复键

时间:2019-01-10 15:17:42

标签: java java-8 hashmap java-stream

我正在创建一个地图,其(键,值)在我的Person对象中将是(名称,地址):

Map<String, String> myMap = persons.stream.collect(Collector.toMap(person.getName(), person.getAddress(), (address1, address2) -> address1));

在重复键的情况下,我想跳过将第二个地址添加到地图的操作,并且还要记录名称。跳过重复的地址我已经可以使用mergeFunction来做,但是为了在这个mergeFunction中记录我需要的人对象名称,例如:

(address1, address2) -> {
                           System.out.println("duplicate "+person.name() + " is found!");
                           return address1;
                        }

将人对象传递给此合并功能使我陷入困境。

4 个答案:

答案 0 :(得分:6)

@Aomine:解决方案看起来不错,对我也适用。只是想确认一下,这次迭代了两次?像下面这样的简单解决方案的原因仅迭代一次,但达到了要求。

Map<String,String> myMap= new HashMap<>();
persons.stream().foreach(item-> {
    if(myMap.containsKey(item.getName()))
        {/*do something*/}
    else 
        myMap.put(item.getName(),item.getAddress());
});

答案 1 :(得分:6)

我相信forEach方法与Map.merge一起使用会更简单并且适合当前用例:

Map<String, String> myMap = new HashMap<>();
persons.forEach(person -> myMap.merge(person.getName(), person.getAddress(), (adrs1, adrs2) -> {
    System.out.println("duplicate " + person.getName() + " is found!");
    return adrs1;
}));

注意Map.merge也使用BiFunctionBinaryOperatortoMap的父对象),因此您可以在此处关联合并功能轻松地将其转换为现有的所需功能。

答案 2 :(得分:1)

如果要在合并功能中访问整个人员对象,请为Function.identity()传递valueMapper

Map<String, Person> myMap = 
        persons.stream()
               .collect(toMap(p -> p.getName(), 
                      Function.identity(), // or p -> p
                     (p1, p2) -> { /* do logic */ }));

但是如您所见,如果您仍然希望将Person作为结果并仍然访问{{1}中的整个Map<String, String>对象,则生成的映射值为Person对象},则可以执行以下操作:

mergeFunction

答案 3 :(得分:1)

这是使用peek

的另一种可能性
import java.util.*;
import java.util.stream.*;

class App {
    public static void main(String[] args) {
        List<Person> persons = Arrays.asList(new Person("foo", "bar"), new Person("baz", "qux"), new Person("foo", "zuz"));

        Set<String> names = new HashSet<>();
        Map<String, String> nameAddress = persons.stream().peek(p -> {
            if (names.contains(p.getName())) {
                System.out.println("Duplicate key being skipped: " + p);
            } else {
                names.add(p.getName());
            }
        }).collect(Collectors.toMap(person -> person.getName(), person -> person.getAddress(), (addr1, addr2) -> addr1));

    }
}

class Person {
    String name;
    String address;

    public Person(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }

    @Override
    public String toString() {
        return name + " " + address;
    }
}

对我来说,上面的代码段输出如下:

Duplicate key being skipped: foo zuz