首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java8StreamAPI-在映射和列表迭代器中转换为循环

Java8StreamAPI-在映射和列表迭代器中转换为循环
EN

Stack Overflow用户
提问于 2018-03-13 23:58:37
回答 1查看 1.1K关注 0票数 1

在下面的代码中,我试图计算一个篮子的总价格,其中篮子是一个HashMap,其中包含产品作为键,数量作为值。促销活动可作为晋升名单提供。

我正在循环每一个地图条目,并为他们中的每一个迭代促销。如果促销匹配,我将使用促销价格(promotion.computeDiscountedPrice())并将促销从列表中删除(因为促销只适用于产品&产品在列表中是唯一的)

如果没有晋升,我们就执行块。

如果(!offerApplied) { /* .*/ }

请您帮助我使用Java8StreamAPI执行同样的操作吗?

代码语言:javascript
复制
BigDecimal basketPrice = new BigDecimal("0.0");
Map<String, Integer> basket = buildBasket(input);
List<Promotion> promotions = getOffersApplicable(basket);

for (Map.Entry<String, Integer> entry : trolley.entrySet()) {
    boolean offerApplied = false;
    Iterator<Promotion> promotionIterator = promotions.iterator();
    while (promotionIterator.hasNext()) {
    Promotion promotion = promotionIterator.next();
    if (entry.getKey().equalsIgnoreCase(offer.getProduct().getProductName())) {
        basketPrice = basketPrice.add(promotion.computeDiscountedPrice());
        offerApplied = true;
        promotionIterator.remove();
        break;
    }
    if (!offerApplied) {
        basketPrice = basketPrice.add(Product.valueOf(entry.getKey()).getPrice()
                        .multiply(new BigDecimal(entry.getValue())));
    }
}
return basketPrice;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-14 05:26:54

最简单、更简洁的解决方案比迭代整个促销列表具有更好的性能,首先创建由产品id标识的促销映射(小写或大写,假设使用equalsIgnoreCase(..)不会发生大小写冲突)。

代码语言:javascript
复制
Map<String, Promotion> promotionByProduct = promotions.stream()
        .collect(Collectors.toMap(prom -> prom.getProduct()
                .getProductName().toLowerCase(), Function.identity()));

这将避免在搜索促销时遍历整个数组,也避免了从其中删除项目,如果是ArrayList,则每次使用删除时都需要将其余的元素转移到左边。

代码语言:javascript
复制
BigDecimal basketPrice = basket.keySet().stream()
        .map(name -> Optional.ofNullable(promotionByProduct.get(name.toLowerCase()))
                .map(Promotion::computeDiscountedPrice) // promotion exists
                .orElseGet(() -> Product.valueOf(name).getPrice()) // no promotion
                .multiply(BigDecimal.valueOf(basket.get(name))))
        .reduce(BigDecimal.ZERO, BigDecimal::add);

它对篮子中的每个产品名称进行迭代,然后检查是否存在促销,它使用computeDiscountedPrice方法,否则它将使用Product.valueOf(..)查找产品并获得价格,然后它将该值与篮子中的产品数量相乘,最后用BigDecimal.add()方法减少结果(添加篮子的所有值)。

需要注意的是,在您的代码中,您不会将quantity的结果乘以promotion.computeDiscountedPrice()的结果(上面的代码确实如此),我不确定这是代码中的类型,还是它的行为方式。

如果实际情况是它的行为方式(您不希望将quantity乘以promotion.computeDiscountedPrice()),则代码如下:

代码语言:javascript
复制
BigDecimal basketPrice = basket.keySet().stream()
        .map(name -> Optional.ofNullable(promotionByProduct.get(name.toLowerCase()))
                .map(Promotion::computeDiscountedPrice)
                .orElseGet(() -> Product.valueOf(name).getPrice()
                        .multiply(BigDecimal.valueOf(basket.get(name)))))
        .reduce(BigDecimal.ZERO, BigDecimal::add);

这里唯一的值乘以quantity将是用Product.valueOf(name).getPrice()获得的产品价格。

最后,另一个选项,全部在一行中,不使用地图(迭代促销)使用第一种方法(最后按数量进行倍数):

代码语言:javascript
复制
BigDecimal basketPrice = basket.keySet().stream()
        .map(name -> promotions.stream()
                .filter(prom -> name.equalsIgnoreCase(prom.getProduct().getProductName()))
                .findFirst().map(Promotion::computeDiscountedPrice) // promotion exists
                .orElseGet(() -> Product.valueOf(name).getPrice()) // no promotion
                .multiply(BigDecimal.valueOf(basket.get(name))))
        .reduce(BigDecimal.ZERO, BigDecimal::add);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49267766

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档