应用流以过滤除一个

时间:2018-10-31 16:04:40

标签: java java-8 java-stream

我有以下课程:

public class Offer {

    private final OfferType type;
    private final BigDecimal price;

    // constructor, getters and setters
}

和枚举类型:

public enum OfferType {
    STANDARD, BONUS;
}

我的用例是输入要约清单作为输入,我想过滤掉所有最便宜的标准要约。所以对于以下输入数据

List<Offer> offers = Arrays.asList(new Offer(OfferType.STANDARD, BigDecimal.valueOf(10.0)),
            new Offer(OfferType.STANDARD, BigDecimal.valueOf(20.0)),
            new Offer(OfferType.STANDARD, BigDecimal.valueOf(30.0)),
            new Offer(OfferType.BONUS, BigDecimal.valueOf(5.0)),
            new Offer(OfferType.BONUS, BigDecimal.valueOf(5.0)));

我希望得到以下结果

[Offer [type=STANDARD, price=10.0], Offer [type=BONUS, price=5.0], Offer [type=BONUS, price=5.0]]

是否存在允许执行此操作的单行语句(使用流或任何第三方库)?

4 个答案:

答案 0 :(得分:4)

虽然没有单个流操作,但

List<Offer> some = offers.stream()
                         .filter(x -> x.getType() != OfferType.STANDARD)
                         .collect(Collectors.toCollection(ArrayList::new));

offers.stream()
      .filter(x -> x.getType() == OfferType.STANDARD)
      .min(Comparator.comparing(Offer::getPrice))
      .ifPresent(some::add);

如果您发现自己经常这样做,可以旋转自定义收集器:

 public static Collector<Offer, ?, List<Offer>> minCollector() {
    class Acc {

        Offer min = null;
        List<Offer> result = new ArrayList<>();

        void add(Offer offer) {
            if (offer.getType() == OfferType.STANDARD) {
                if (min == null) {
                    min = offer;
                } else {
                    min = offer.getPrice()
                               .compareTo(min.getPrice()) > 0 ? min : offer;
                }
            } else {
                result.add(offer);
            }
        }

        Acc combine(Acc another) {
            this.min = reduceMin(this.min, another.min);
            result.addAll(another.result);
            return this;
        }

        List<Offer> finisher() {
            result.add(min);
            return result;
        }

        private Offer reduceMin(Offer left, Offer right) {
            return Collections.min(Arrays.asList(left, right),
                                   Comparator.nullsLast(Comparator.comparing(Offer::getPrice)));
        }
    }

    return Collector.of(Acc::new, Acc::add, Acc::combine, Acc::finisher);
}

用法为:

List<Offer> result = offers.stream()
                           .collect(minCollector());

答案 1 :(得分:2)

  

是否存在单行语句(使用流或任何第三方)   库)允许这样做吗?

两次执行操作,将更具可读性。

1)计算Standard类型商品的最便宜价格:

Optional<Offer> minPriceOffer = 
offers.stream()
      .filter(o -> o.getType() == OfferType.STANDARD)
      .min(Comparator.comparing(Offer::getPrice));

2)在收集的清单中排除此价格的Standard个出价:

List<Offer> offersFiltered = 
offers.stream()
      .filter(o -> {  
               if (o.getType() == OfferType.STANDARD                         
                    && !o.getPrice().equals(minPriceOffer.get().getPrice())) 
                  return false;
               // else
               return true;
             }
       )
      .collect(toList();

答案 2 :(得分:2)

以下是两个流:

  1. 按商品类型分组
  2. 将每个组的报价转换为流
  3. 选择standard个要约,对其进行排序,并将其限制为1个元素(按价格最小)
  4. 合并两个流

代码如下:

List<Offer> result = offers.stream()
        .collect(Collectors.groupingBy(Offer::getType))
        .entrySet()
        .stream()
        .flatMap(entry -> entry.getKey() == OfferType.STANDARD ? 
                            entry.getValue().stream()
                            .sorted(Comparator.comparing(Offer::getPrice))
                            .limit(1)
                          :  entry.getValue().stream())
        .collect(Collectors.toList());

答案 3 :(得分:0)

List<Offer> result = offers.stream().filter(e -> OfferType.BONUS == e.getType()).collect(toList());
offers.stream().filter(e -> OfferType.STANDARD == e.getType()).findAny().ifPresent(result::add);