Java 8 如何按枚举类型合并多个列表

huangapple go评论110阅读模式
英文:

Java 8 how to merge multiple lists by enum type

问题

  1. 如何在Java 8中按枚举类型合并多个列表
  2. 我有两个列表
  3. List<StatusSummary> listA // 因为有4个枚举类型,所以有4个项
  4. List<StatusSummary> listB // 因为有4个枚举类型,所以有4个项
  5. class StatusSummary {
  6. private StatusEnum resourcesStatus; // 4个状态:TypeA、TypeB、TypeC、TypeD
  7. private Integer count;
  8. }
  9. 我想要有一个列表其中包含每个 `resourcesStatus: TypeA, TypeB, TypeC, TypeD` 4个项并且 `count` 字段中的元素求和如下
  10. List<StatusSummary> listA+B4个对象
  11. (resourcesStatus: TypeA, count: 3), (resourcesStatus: TypeB, count: 99), (resourcesStatus: typeC, count: 322), (resourcesStatus: TypeD, count: 2)
  12. 到目前为止我实现了类似以下的代码
  13. listA
  14. .getResourcesStatus()
  15. .forEach(la -> listB.getResourcesStatus().stream()
  16. .filter(lb -> lb.getResourcesStatus() == la.getResourcesStatus())
  17. .forEach(lb -> result.add(new StatusSummary()
  18. .count(la.getCount() + lb.getCount())
  19. .status(la.getStatus()))));
英文:

How to merge multiple lists in Java 8 by enum type?

I have 2 lists:

  1. List&lt;StatusSummary&gt; listA //4 items because we have 4 enum types
  2. List&lt;StatusSummary&gt; listB //4 items because we have 4 enum types
  3. class StatusSummary {
  4. private StatusEnum resourcesStatus; //4 statuses: TypeA, TypeB, TypeC, TypeD
  5. private Integer count;
  6. }

I want to have one list consisting of 4 items for each resourcesStatus: TypeA, TypeB, TypeC, TypeD with the sum of elements in count field like:

  1. List&lt;StatusSummary&gt; listA+B with 4 objects:
  2. (resourcesStatus: TypeA, count: 3), (resourcesStatus: TypeB, count:99), (resourcesStatus: typeC, count:322), (resourcesStatus: TypeD, count:2)

So far I implemented something like this:

  1. listA
  2. .getResourcesStatus()
  3. .forEach(la -&gt; listB.getResourcesStatus().stream()
  4. .filter(lb -&gt; lb.getResourcesStatus() == la.getResourcesStatus())
  5. .forEach(lb -&gt; result.add(new StatusSummary()
  6. .count(la.getCount() + lb.getCount())
  7. .status(la.getStatus()))));

答案1

得分: 3

你可以使用 Collectors.toMap。以 ResourcesStatus 为键,使用合并函数将两个具有 count 字段的 StatusSummary 合并为相同的 ResourcesStatus,然后您将获得类型为 Map<StatusEnum, StatusSummary> 的映射,然后可以使用 .values()ArrayList 中获取映射的值。

  1. List<StatusSummary> newList =
  2. new ArrayList<>(
  3. Stream.of(listA, listB)
  4. .flatMap(Collection::stream)
  5. .collect(Collectors.toMap(
  6. e -> e.getResourcesStatus(),
  7. i -> i,
  8. (a, b) -> new StatusSummary(
  9. a.getResourcesStatus(),
  10. a.getCount() + b.getCount()
  11. )))
  12. .values());
英文:

You can use Collectors.toMap. Map by ResourcesStatus and merge two StatusSummary with count field in merge-function for the same ResourcesStatus then you get Map&lt;StatusEnum, StatusSummary&gt; and then get values of the map using .values() in ArrayList.

  1. List&lt;StatusSummary&gt; newList =
  2. new ArrayList&lt;&gt;(
  3. Stream.of(listA, listB)
  4. .flatMap(Collection::stream)
  5. .collect(Collectors.toMap(e -&gt; e.getResourcesStatus(), i -&gt; i,
  6. (a,b) -&gt; new StatusSummary(a.getResourcesStatus(),
  7. a.getCount() + b.getCount())))
  8. .values());

答案2

得分: 2

问题使用 forEach

就我所见,您当前使用 forEach 的解决方案,将流式 API 视为简单的带有附加功能的 for 循环。您违反了 [tag:java-stream] 的 Side-effects 原则,简而言之,该原则指出流不应在执行管道操作时修改另一个集合。我尚未测试您的代码,但这不是您应该处理流的方式。

可能的解决方案之一

您可以使用 Collectors.groupingByCollectors.summingInt 来获得带有状态和计数总和的 Map&lt;StatusEnum, Integer&gt;。然后,可以将每个条目转换为 StatusSummary 并将其收集为 List

  1. List&lt;StatusSummary&gt; list = Stream.of(listA, listB)
  2. .flatMap(List::stream)
  3. .collect(Collectors.groupingBy( // Map&lt;StatusSummary, Integer&gt;
  4. StatusSummary::getResourcesStatus, // .. 将 StatusEnum 作为键
  5. Collectors.summingInt(StatusSummary::getCount))) // .. 将 Integer 作为值(总和)
  6. .entrySet()
  7. .stream() // Stream&lt;Entry&lt;..&gt;&gt;
  8. .map(e -&gt; new StatusSummary(e.getKey(), e.getValue())) // Stream&lt;StatusSummary&gt;
  9. .collect(Collectors.toList()); // List&lt;StatusSummary&gt;

... 或者使用 Collectors.collectingAndThen(不少 verbose):

  1. List&lt;StatusSummary&gt; list1 = Stream.of(listA, listB, listC)
  2. .flatMap(List::stream)
  3. .collect(Collectors.collectingAndThen(
  4. Collectors.groupingBy(
  5. StatusSummary::getResourcesStatus,
  6. Collectors.summingInt(StatusSummary::getCount)),
  7. map -&gt; map.entrySet().stream()
  8. .map(e -&gt; new StatusSummary(e.getKey(), e.getValue()))
  9. .collect(Collectors.toList())));
英文:

Problem using forEach

As far as I see your current solution using forEach, you approach to Stream API as it would be a simple for-loop with additional features. You violate the Side-effects principle of [tag:java-stream] which in a nutshell says that a stream shouldn't modify another collection while performing the actions through the pipelines. I haven't tested your code, however, this is not a way you should treat streams.

One of the possible solutions

You can use Collectors.groupingBy with Collectors.summingInt to get Map&lt;StatusEnum, Integer&gt; with the status and a sum of counts. Each entry then can be transformed into StatusSummary and colleted as List:

  1. List&lt;StatusSummary&gt; list = Stream.of(listA, listB)
  2. .flatMap(List::stream)
  3. .collect(Collectors.groupingBy( // Map&lt;StatusSummary, Integer&gt;
  4. StatusSummary::getResourcesStatus, // .. StatusEnum as key
  5. Collectors.summingInt(StatusSummary::getCount))) // .. Integer as value (sum)
  6. .entrySet()
  7. .stream() // Stream&lt;Entry&lt;..&gt;&gt;
  8. .map(e -&gt; new StatusSummary(e.getKey(), e.getValue())) // Stream&lt;StatusSummary&gt;
  9. .collect(Collectors.toList()); // List&lt;StatusSummary&gt;

... or using Collectors.collectingAndThen (not less verbose):

  1. List&lt;StatusSummary&gt; list1 = Stream.of(listA, listB, listC)
  2. .flatMap(List::stream)
  3. .collect(Collectors.collectingAndThen(
  4. Collectors.groupingBy(
  5. StatusSummary::getResourcesStatus,
  6. Collectors.summingInt(StatusSummary::getCount)),
  7. map -&gt; map.entrySet().stream()
  8. .map(e -&gt; new StatusSummary(e.getKey(), e.getValue()))
  9. .collect(Collectors.toList())));

huangapple
  • 本文由 发表于 2020年8月20日 20:25:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63505072.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定