Group list of objects into Map<String, Boolean> with value being true if any object in group has field set as true using Java stream API

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

Group list of objects into Map<String, Boolean> with value being true if any object in group has field set as true using Java stream API

问题

在一个Java 17项目中,我有一个对象集合,其中有一个String字段propGroupName代表该对象所属的组,还有一个Boolean字段propValActive代表该对象是否在内部标记为活动状态。

我想要按照字符串字段对这些对象进行分组,生成一个Map<String, Boolean>,其中键是String字段,Boolean值为false,如果该组中的所有布尔值都为false,如果该组中的一个或多个布尔值为false,则为true。我有一个使用简单的for循环的工作实现,但我想知道是否有一种方法可以通过Java Stream API来进行这种分组,最好是以短路方式?目标是我想知道每个组中是否有任何标记为活动的对象。

我目前有这个实现,它不使用Streams API并且不进行短路:

  1. public Map<String, Boolean> determineActiveGroups(
  2. HashMap<String, PropertyValueDefinitionGroupView> standardPvdgMap) {
  3. Map<String, Boolean> activeGroupsMap = new HashMap<String, Boolean>();
  4. for (PropertyValueDefinitionGroupView pvdgView : standardPvdgMap.values()) {
  5. if (pvdgView.getPropGroupOid() == null) {
  6. continue;
  7. }
  8. activeGroupsMap.putIfAbsent(pvdgView.getPropGroupName(), false);
  9. if (pvdgView.getPropValActive()) {
  10. activeGroupsMap.put(pvdgView.getPropGroupName(), true);
  11. }
  12. }
  13. return activeGroupsMap;
  14. }

我在其他地方有一段不同的代码,做类似的事情,但它保留了列表,我设法调整了类似的代码,但我不知道可以使用什么谓词来完成它。我假设它将使用anyMatch,但我不知道如何集成它:

  1. Map<String, Boolean> activeGroups = standardPvdgMap.values().stream()
  2. .collect(Collectors.groupingBy(PropertyValueDefinitionGroupView::getPropGroupName, ???????));

这是你需要填充的部分,用于计算每个组是否有活动对象的布尔值。你可以使用Collectors.reducing来实现这一点。下面是如何完成这个流操作:

  1. Map<String, Boolean> activeGroups = standardPvdgMap.values().stream()
  2. .collect(Collectors.groupingBy(
  3. PropertyValueDefinitionGroupView::getPropGroupName,
  4. Collectors.reducing(false, PropertyValueDefinitionGroupView::getPropValActive, Boolean::logicalOr)
  5. ));

这将根据propGroupName字段对对象进行分组,并计算每个组中是否有活动对象,如果有任何一个对象的propValActive为true,则组的值为true,否则为false。这使用了Boolean::logicalOr来逻辑或所有布尔值,以得出每个组的最终布尔值。

英文:

In a Java 17 project, I have a collection of objects with a String field propGroupName representing the group this object belongs to and a Boolean field propValActive representing whether this object is flagged as active internally.

I want to aggregate these objects by the string field into a Map<String, Boolean> with the key being the String field and the Boolean being false if all the booleans in the group are false and true if 1 or more of the booleans in the group are false. I have a working implementation with a simple for loop, but I want to know if there is a way to do this grouping through the Java Stream API, preferably in a way that short circuits? The goal is that I want to know of every group whether there are any objects in that group flagged as active.

I currently have this implementation which doesn't use the Streams API and doesn't short circuit:

  1. public Map&lt;String, Boolean&gt; determineActiveGroups(
  2. HashMap&lt;String, PropertyValueDefinitionGroupView&gt; standardPvdgMap) {
  3. Map&lt;String, Boolean&gt; activeGroupsMap = new HashMap&lt;String, Boolean&gt;();
  4. for (PropertyValueDefinitionGroupView pvdgView : standardPvdgMap.values()) {
  5. if(pvdgView.getPropGroupOid() == null) {
  6. continue;
  7. }
  8. activeGroupsMap.putIfAbsent(pvdgView.getPropGroupName(), false);
  9. if(pvdgView.getPropValActive()) {
  10. activeGroupsMap.put(pvdgView.getPropGroupName(), true);
  11. }
  12. }
  13. return activeGroupsMap;
  14. }

I have a different bit of code somewhere else that does something similar, but it retains the lists, and I managed to adapt something similar for what I need but I don't know what predicate I can use to finish it with. I assume it's going to use anyMatch, but I have no idea how to integrate it:

  1. Map&lt;String, Boolean&gt; activeGroups = standardPvdgMap.values().stream()
  2. .collect(Collectors.groupingBy(PropertyValueDefinitionGroupView::getPropGroupName, ???????));

答案1

得分: 1

groupingBy 是一个非常强大的收集器:

  1. public Map<String, Boolean> determineActiveGroups(Map<String, PropertyValueDefinitionGroupView> standardPvdgMap) {
  2. return standardPvdgMap.values()
  3. .stream()
  4. .filter(pvdgView -> pvdgView.getPropGroupOid() != null)
  5. .collect(Collectors.groupingBy(
  6. PropertyValueDefinitionGroupView::getPropGroupName,
  7. Collectors.mapping(
  8. PropertyValueDefinitionGroupView::getPropValActive,
  9. Collectors.reducing(false, (a, b) -> a || b))
  10. ));
  11. }

关键在于你可以在下游进一步应用其他收集器。在这种情况下,我映射到标志,然后使用逻辑或操作符来减少这些标志。

英文:

groupingBy is such a powerful collector :

  1. public Map&lt;String, Boolean&gt; determineActiveGroups(Map&lt;String, PropertyValueDefinitionGroupView&gt; standardPvdgMap) {
  2. return standardPvdgMap.values()
  3. .stream()
  4. .filter(pvdgView -&gt; pvdgView.getPropGroupOid() != null)
  5. .collect(Collectors.groupingBy(
  6. PropertyValueDefinitionGroupView::getPropGroupName,
  7. Collectors.mapping(
  8. PropertyValueDefinitionGroupView::getPropValActive,
  9. Collectors.reducing(false, (a, b) -&gt; a || b))
  10. ));
  11. }

The trick is knowing that you can apply further collectors on the downstream. In this case I map to the flag, and then reduce the flags using the logical or.

答案2

得分: 0

你试过使用以下方法吗:Collectors.toMap(Function, Function, BinaryOperator)

  1. standardPvdgMap.values()
  2. .stream()
  3. .filter(pvdgView -> pvdgView.getPropGroupOid() != null)
  4. .collect(toMap(it -> it.getPropGroupName(),
  5. it -> it.getPropValActive(),
  6. (a, b) -> a || b)));
英文:

Have you ever tried: Collectors.toMap(Function, Function, BinaryOperator)?

  1. standardPvdgMap.values()
  2. .stream()
  3. .filter(pvdgView -&gt; pvdgView.getPropGroupOid() != null)
  4. .collect(toMap(it -&gt; it.getPropGroupName(),
  5. it -&gt; it.getPropValActive(),
  6. (a, b) -&gt; a || b)));

huangapple
  • 本文由 发表于 2023年6月1日 23:18:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76383416.html
匿名

发表评论

匿名网友

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

确定