Java Apply stream可筛选出除一个元素之外满足条件的所有元素

Java Apply stream可筛选出除一个元素之外满足条件的所有元素,java,java-8,java-stream,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; } 我的用例是,有一个报价列表作为输入,我想过滤掉所有的标准报价,除了最便宜的报价。所以对于下面的输入数据

我有以下课程:

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)));
是否有允许这样做的单行语句(使用streams或任何第三方库)

List result=offers.stream().filter(e->OfferType.BONUS==e.getType()).collect(toList());
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);
offers.stream().filter(e->OfferType.STANDARD==e.getType()).findAny().ifPresent(结果::添加);
不使用单流操作,但:

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);
List some=offers.stream()
.filter(x->x.getType()!=OfferType.STANDARD)
.collect(收集器.toCollection(ArrayList::new));
offers.stream()
.filter(x->x.getType()==OfferType.STANDARD)
.min(比较器比较(报价::getPrice))
.ifPresent(一些::添加);
如果您发现自己经常这样做,您可能会选择一个自定义收集器:

 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);
}
公共静态收集器minCollector(){
等级Acc{
Offer min=null;
列表结果=新建ArrayList();
无效添加(报价){
if(offer.getType()==OfferType.STANDARD){
if(min==null){
最小=报价;
}否则{
min=offer.getPrice()
.compareTo(min.getPrice())>0?min:报价;
}
}否则{
结果。添加(报价);
}
}
Acc联合收割机(Acc另一个){
this.min=reduceMin(this.min,另一个.min);
result.addAll(另一个.result);
归还这个;
}
列表整理器(){
结果:添加(分钟);
返回结果;
}
私人报价减少(报价左,报价右){
返回Collections.min(Arrays.asList(左、右),
nullsLast(Comparator.comparing(Offer::getPrice));
}
}
返回收集器of(Acc::new、Acc::add、Acc::combine、Acc::finisher);
}
其用途是:

List<Offer> result = offers.stream()
                           .collect(minCollector());
List result=offers.stream()
.collect(minCollector());
是否有单行语句(使用streams或任何第三方) 图书馆)允许这样做吗

把事情分两次做,可读性会更好

1) 计算
标准
类型优惠的最便宜价格:

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

以下是两条流:

  • 按报价类型分组
  • 将每个组的报价转换为流
  • 选择
    标准
    报价,对其进行排序,并将其限制为1个元素(最低价格)
  • 合并两条流
  • 代码如下所示:

    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());
    
    List result=offers.stream()
    .collect(收集器.groupingBy(Offer::getType))
    .entrySet()
    .stream()
    .flatMap(entry->entry.getKey()==OfferType.STANDARD?
    entry.getValue().stream()
    .sorted(Comparator.comparing(Offer::getPrice))
    .限额(1)
    :entry.getValue().stream())
    .collect(Collectors.toList());
    
    我想过滤掉所有标准的,除了最便宜的。-你这么说是什么意思?“标准的”是指“类型字段上有价值的OfferType.standard”和“最便宜的”是指“标准报价中价格最低的”那么type=奖金如何成为你预期产出的一部分呢?@NicholasK,我不知道你是怎么理解我的描述的,但我的目的是输出所有的奖金优惠,只有一个标准优惠,价格最低,
    排序
    +
    限制(1)
    最好是
    min
    @Eugene我想这是与你的答案的比较。只要可能,我总是选择运行一次流。这个解决方案避免在
    提供的
    @nullpointer上运行两个流,我可以很好地使用
    min
    ,但是我需要一个流,因为这是
    flatMap
    @ernest_k得到它的一个参数,为了
    .min(Comparator.comparating(Offer::getPrice)).stream()
    (Java9+
    .min(Comparator.comparating(Offer::getPrice))而忽略了它
    是你打败我的地方:)@nullpointer。。或者是一个自定义收集器,但编写它却花了一段时间,这正是我所依赖的简单for循环方法
    List result=new ArrayList();BigDecimal最小值=BigDecimal.0;for(Offer-Offer:offers){switch(Offer.getType()){case-STANDARD:if(Offer.getPrice().compareTo(min)<0){min=Offer.getPrice();}break;case-BONUS:default:result.add(Offer);break;}}result.add(新报价(OfferType.STANDARD,min))。类似的累加器。@FedericoPeraltaSchaffner我的错误解释-删除了注释,在所有合并器运行后,将运行finisher,此时该min将被放入结果中。您注意到任何min都可能为空!(我错过了)。。。变量可以是
    BinaryOperator.minBy(Comparator.nullslat(Comparator.comparating(Offer::getPrice)))。应用(左、右)
    ,因为我们只想排除标准报价(而不是其他类型)的价格。
    .min(Offer::getPrice)
    不起作用;您需要
    .min(Comparator.comparating(Offer::getPrice))
    。另一方面,您可以简化第二个谓词:
    .filter(o->o.getType()!=OfferType.STANDARD | | o.getPrice().equals(minPriceOffer.get().getPrice())
    。您不需要
    isPresent()
    ,因为当遇到
    OfferType.STANDARD
    时,可选项不能为空。原则上,您也可以使用
    filter(o->o.getType()!=OfferType.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();
    
    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());