baao
baao

Reputation: 73251

stream creates an additional list - how to avoid

I'm having a problem figuring out the right way to stream and collect my data.

The stream is the following

  public List<List<CalculatedItemCostPerStore>> getCalcualtedItemCostPerStore() {
    var it = item
        .getQuantities().stream().map(quantities -> {
          Store.StoreCosts<CostType, BigDecimal> storeCosts = quantities.getStore().getStoreCosts();
          return new CalculatedItemCostPerStore(quantities.getStore().getName(), new TreeSet<>(quantities
              .getItemCostEvents()
              .stream()
              .map(e -> new CalculatedItemCost(e.getCostTrigger(), e.getTriggerQuantity().multiply(storeCosts.get(e.getCostTrigger()))))
              .collect(
                  Collectors.toMap(CalculatedItemCost::getCostType, Function.identity(), (a, b) -> new CalculatedItemCost(a.getCostType(), a.getCost().add(b.getCost())))
              ).values()));
        }).collect(Collectors.groupingBy(CalculatedItemCostPerStore::getStore)).values().stream().collect(Collectors.toList());
    return it;
  }

Get's streamed into

  @Data
  @AllArgsConstructor
  static class CalculatedItemCost implements Comparable<CalculatedItemCost> {
    private CostType costType;
    private BigDecimal cost;

    @Override
    public int compareTo(CalculatedItemCost o) {
      return this.costType.toString().compareTo(o.getCostType().toString());
    }
  }

  @Data
  @AllArgsConstructor
  static class CalculatedItemCostPerStore {
    private String store;
    private TreeSet<CalculatedItemCost> calculatedItemCosts;
  }

and itemCostEvents are a list of

{
  "createdAt": "2018-08-29T00:00:00",
  "costTrigger": "STORAGE_COST_PER_CBM_PER_DAY",
  "triggerQuantity": 33
}

above stream creates a result that is represented by below json. As you can see it's an List<List<CalculatedItemCostPerStore>>

"calcualtedItemCostPerStore": [
    [
      {
        "store": "foo",
        "calculatedItemCosts": [
          {
            "costType": "ADDITIONAL_COST_OFFICE_PER_HOUR",
            "cost": 1368
          },
          {
            "costType": "STORAGE_COST_PER_CBM_PER_DAY",
            "cost": 287.1
          }
        ]
      }
    ],
    [
      {
        "store": "bar",
        "calculatedItemCosts": [
          {
            "costType": "ADDITIONAL_COST_OFFICE_PER_HOUR",
            "cost": 38
          }
        ]
      }
    ]
  ]

There can be any number of occurrences of quantities, of which each can have one store.

What I would like to get is a single List<CalculatedItemCostPerShop> like shown below

"calcualtedItemCostPerStore": [
    {
        "store": "foo",
        "calculatedItemCosts": [
            {
                "costType": "ADDITIONAL_COST_OFFICE_PER_HOUR",
                "cost": 1368
            },
            {
                "costType": "STORAGE_COST_PER_CBM_PER_DAY",
                "cost": 287.1
            }
        ]
    },
    {
        "store": "bar",
        "calculatedItemCosts": [
            {
                "costType": "ADDITIONAL_COST_OFFICE_PER_HOUR",
                "cost": 38
            }
        ]
    }
 ]

How would I need to adapt my stream to get above result?

Upvotes: 2

Views: 91

Answers (1)

baao
baao

Reputation: 73251

Solved it thanks to @ernest_k - using flatMap on the .values()

public List<CalculatedItemCostPerStore> getCalcualtedItemCostPerStore() {
    return item
        .getQuantities().stream().map(quantities -> {
          Store.StoreCosts<CostType, BigDecimal> storeCosts = quantities.getStore().getStoreCosts();
          return new CalculatedItemCostPerStore(quantities.getStore().getName(), new TreeSet<>(quantities
              .getItemCostEvents()
              .stream()
              .map(e -> new CalculatedItemCost(e.getCostTrigger(), e.getTriggerQuantity().multiply(storeCosts.get(e.getCostTrigger()))))
              .collect(
                  Collectors.toMap(CalculatedItemCost::getCostType, Function.identity(), (a, b) -> new CalculatedItemCost(a.getCostType(), a.getCost().add(b.getCost())))
              ).values()));
        })
        .collect(Collectors.groupingBy(CalculatedItemCostPerStore::getStore))
        .values()
        .stream()
        .flatMap(Collection::stream).collect(Collectors.toList())
        ;
  }

Upvotes: 1

Related Questions