使用流生成地图时忽略重复项

Pat*_*tan 226 java java-8 java-stream

Map<String, String> phoneBook=people.stream()
                                    .collect(toMap(Person::getName, Person::getAddress));
Run Code Online (Sandbox Code Playgroud)

重复发生时,我得到重复的密钥异常.

是否可以忽略在重复发生时将值添加到映射?

当存在重复时,它应该继续忽略该重复键.

Tun*_*aki 396

这可以使用以下mergeFunction参数Collectors.toMap(keyMapper, valueMapper, mergeFunction):

Map<String, String> phoneBook = 
    people.stream()
          .collect(Collectors.toMap(
             Person::getName,
             Person::getAddress,
             (address1, address2) -> {
                 System.out.println("duplicate key found!");
                 return address1;
             }
          ));
Run Code Online (Sandbox Code Playgroud)

mergeFunction是一个函数,它对与同一个键相关的两个值进行操作.adress1对应于收集元素时遇到的第一个地址,adress2对应于遇到的第二个地址:这个lambda告诉保留第一个地址并忽略第二个地址.

  • 我很困惑,为什么不允许重复**值**(不是键)?以及如何允许重复值? (5认同)
  • @djkelly99 其实你可以,你只需要让你的重映射函数返回 `null`。请参阅 [toMap 文档](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Collectors.html#toMap(java.util.function. Function,java.util.function.Function,java.util.function.BinaryOperator)) 指向 [merge doc](https://docs.oracle.com/en/java/javase/11/docs/api/java .base/java/util/Map.html#merge(K,V,java.util.function.BiFunction)) 说明 _如果重映射函数返回 null,则删除映射。_ (5认同)
  • 我们不应该返回 address2 来模仿标准地图行为吗?如果这是每个而不是收集的标准行为将是放在第二个地址上会清除第一个地址。因此,为了避免代码重构时行为发生变化,address2 是合理的选择。 (4认同)
  • @Hendy Irawan:允许重复的值。合并功能是在具有相同键**的两个值之间进行选择(或合并)。 (3认同)
  • 如果发生冲突,是否可以完全忽略此条目?基本上,如果我遇到重复的键,我根本不希望添加它们。在上面的示例中,我不需要地图中的address1或address2。 (2认同)

ala*_*ter 85

JavaDocs所述:

如果映射的键包含重复项(根据 Object.equals(Object)),IllegalStateException则在执行收集操作时抛出a.如果映射的键可能有重复,请toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)改用.

所以你应该使用toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction).只需提供合并功能,即确定需要将哪一个重复放入地图中.例如,如果您不关心哪一个,只需打电话

Map<String, String> phoneBook = people.stream()
  .collect(Collectors.toMap(Person::getName, Person::getAddress, (a1, a2) -> a1));
Run Code Online (Sandbox Code Playgroud)

  • 如果不正确理解,这可能会导致严重的数据丢失。 (3认同)
  • 使用`Collectors.toMap`或进行静态导入 (2认同)
  • 嗯,是。在大多数情况下,必须以某种方式组合重复的值,否则会引发异常(默认情况下,这是正确的行为)。但在某些罕见的情况下,您需要忽略重复项,这就是问题所在。 (2认同)

Dhe*_*rik 5

@alaster答案对我有很大帮助,但是如果有人试图对信息进行分组,我想添加一些有意义的信息。

例如,如果您有两个产品Orders相同code但不同quantity的产品,并且您希望将数量相加,则可以执行以下操作:

List<Order> listQuantidade = new ArrayList<>();
listOrders.add(new Order("COD_1", 1L));
listOrders.add(new Order("COD_1", 5L));
listOrders.add(new Order("COD_1", 3L));
listOrders.add(new Order("COD_2", 3L));
listOrders.add(new Order("COD_3", 4L));

listOrders.collect(Collectors.toMap(Order::getCode, o -> o.getQuantity(), (o1, o2) -> o1 + o2));
Run Code Online (Sandbox Code Playgroud)

结果:

{COD_3=4, COD_2=3, COD_1=9}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

99441 次

最近记录:

6 年,5 月 前