【问题标题】:Streams on nested map嵌套地图上的流
【发布时间】:2019-01-10 02:31:01
【问题描述】:

我有以下用例。我有一个具有以下结构的嵌套地图:

Map<String, Map<WorkType, List<CostLineItem>>>

我必须遍历地图并获取 CLObject 列表。如果列表中的单个条目的标识符为空。我必须为每个 EnumType 生成唯一标识符。我不确定如何使用流来做到这一点?遵循迭代逻辑将清楚我想要完成什么

for(Map.Entry<String, Map<WorkType, List<CostLineItem>>> cliByWorkTypeIterator: clisByWorkType.entrySet()) {
       Map<WorkType, List<CostLineItem>> entryValue = cliByWorkTypeIterator.getValue();
       for(Map.Entry<WorkType, List<CostLineItem>>cliListIterator : entryValue.entrySet()) {
           List<CostLineItem> clis = cliListIterator.getValue();
           //if any CLI settlementNumber is zero this means we are in standard upload
           //TODO: Should we use documentType here? Revisit this check while doing dispute file upload
           if(clis.get(0).getSettlementNumber() == null) {
               clis.forEach(f -> f.toBuilder().settlementNumber(UUID.randomUUID().toString()).build());
           }
       }
   } 

嵌套循环使代码有点样板和肮脏。有人可以帮我处理流吗?

【问题讨论】:

  • Streams 并没有真正的帮助,因为问题首先在于嵌套地图。列表映射的映射是一种明确的代码气味,再多的流也不会让它消失。
  • 您的预期结果是什么?
  • CostLineItem 是根据 workType 和 string(一些标识符)分组的。如果 CostLineItem.settlementNumber 为 null ,我必须将结算号分配给它。请查看嵌套的 for 循环。道歉..我知道它很笨拙。我会要求看看我们是否可以简化循环以实现类似的结果。
  • 当你只对values()感兴趣时停止迭代entrySet(),你的代码会变得更简单:for( Map&lt;WorkType, List&lt;CostLineItem&gt;&gt; map: clisByWorkType.values()) { for(List&lt;CostLineItem&gt; clis: map.values()) { your-if-statement } }...

标签: java java-8 hashmap java-stream


【解决方案1】:

您可以使用flatMap 遍历所有内部Maps 的所有List&lt;CostLineItem&gt; 值。

clisByWorkType.values() // returns Collection<Map<WorkType, List<CostLineItem>>>
              .stream() // returns Stream<Map<WorkType, List<CostLineItem>>>
              .flatMap(v->v.values().stream()) // returns Stream<List<CostLineItem>>
              .filter(clis -> clis.get(0).getSettlementNumber() == null) // filters that Stream
              .forEach(clis -> {do whatever logic you need to perform on the List<CostLineItem>});

【讨论】:

  • 谢谢。您能否提供 cmets 以便我更好地理解它
  • @user3681970 确定。
【解决方案2】:
clisByWorkType.values()
              .stream()
              .flatMap(e -> e.values().stream())
              .filter(clis -> clis.get(0).getSettlementNumber() == null)
              .flatMap(Collection::stream)
              .forEach(f -> f.toBuilder().settlementNumber(UUID.randomUUID().toString()).build());

【讨论】:

  • @Eugene 是的,刚刚忙于复制帖子中的确切代码。
【解决方案3】:

以下相当于你的for循环:

clisByWorkType.entrySet()
    .map(Map.Entry::getValue) // cliByWorkTypeIterator.getValue();
    .flatMap(m -> m.entrySet().stream())
    .map(Map.Entry::getValue)
    .map(CostLineItem::getValue)
    .filter(clis.get(0).getSettlementNumber() == null) //filter before flattening
    .flatMap(List::stream)
    .forEach(f -> f.toBuilder().settlementNumber(UUID.randomUUID().toString()).build());

【讨论】:

  • 我必须说你们“伙计们”太棒了。您能否详细解释一下 CostLineItem::getValue 正在做什么?恐怕。我一般不会更改我不完全理解的代码
猜你喜欢
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
  • 2017-11-02
相关资源
最近更新 更多