Java Streams在reduce之后对值进行排序

Java Streams在reduce之后对值进行排序,java,java-8,java-stream,Java,Java 8,Java Stream,我只是试着理解Java中的流,我停留在排序阶段。 我的目的是用一条溪流得到最昂贵的蔬菜比萨饼。在这一点上,我得到了比萨饼的价格,但我不能排序。谁能告诉我该怎么做 我试着这样做: pizzas.stream() .flatMap(pizza -> Stream.of(pizza.getIngredients()) .filter(list -> list.stream().noneMatch(Ingredient::isMeat)) .m

我只是试着理解Java中的流,我停留在排序阶段。 我的目的是用一条溪流得到最昂贵的蔬菜比萨饼。在这一点上,我得到了比萨饼的价格,但我不能排序。谁能告诉我该怎么做

我试着这样做:

pizzas.stream()
    .flatMap(pizza -> Stream.of(pizza.getIngredients())
        .filter(list -> list.stream().noneMatch(Ingredient::isMeat))
            .map(list -> list.stream().map(Ingredient::getPrice).reduce(0,(a, b) -> a + b))
            .sorted((o1, o2) -> o1.intValue() - o2.intValue())
            )
    .forEach(System.out::println);
此代码返回比萨饼的未排序值。

import java.util.Collection;
import java.util.Collection;
import java.util.Comparator;

interface Pizza {
    interface Ingredient {
        boolean isMeat();

        int getPrice();
    }

    Collection<Ingredient> getIngredients();

    static boolean isVegetarian(Pizza pizza) {
        return pizza.getIngredients().stream().noneMatch(Ingredient::isMeat);
    }

    static int price(Pizza pizza) {
        return pizza.getIngredients().stream().mapToInt(Ingredient::getPrice).sum();
    }

    static Pizza mostExpensiveVegetarianPizza(Collection<Pizza> pizzas) {
        return pizzas.stream()
                     .filter(Pizza::isVegetarian)
                     .max(Comparator.comparingInt(Pizza::price))
                     .orElseThrow(() -> new IllegalArgumentException("no veggie pizzas"));
    }
}
导入java.util.Comparator; 界面比萨饼{ 界面成分{ 布尔isMeat(); int getPrice(); } 收集材料(); 静态布尔值是素食者(比萨饼){ 返回pizza.get配料().stream().noneMatch(配料::isMeat); } 静态整数价格(比萨饼){ 返回pizza.get配料().stream().mapToInt(配料::getPrice.sum(); } 静态比萨莫斯特克斯素食比萨(集合比萨){ return pizzas.stream() .filter(比萨饼::Is素食) .max(比较器比较(比萨饼:价格)) .orElseThrow(()->新的IllegalArgumentException(“无蔬菜比萨饼”); } }

如果希望
component.getPrice()
返回一个
double
,可以在
Pizza.price()
中使用
Stream.mapToDouble()
Comparator.comparingDouble()
中使用
Pizza.mostexpensivevegetrainepizza()
中的
。我将一些流封装在Pizza类中以提高易读性

配料

public class Ingredient {
private String name;
private double price;
private boolean meat;

public Ingredient(String name, double price, boolean meat) {
    this.name = name;
    this.price = price;
    this.meat = meat;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public double getPrice() {
    return price;
}

public void setPrice(double price) {
    this.price = price;
}

public boolean isMeat() {
    return meat;
}

public void setMeat(boolean meat) {
    this.meat = meat;
}

}
披萨

公共级比萨饼{
私有字符串名称;
私人成分清单;
公共比萨饼(串名、配料表){
this.name=名称;
这个。成分=成分;
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共列表{
返回成分;
}
公共成分(列出成分){
这个。成分=成分;
}
公共布尔值isVegan(){
返回(配料!=null)?配料.stream().noneMatch(配料::isMeat)
:假;
}
公共双getTotalCost(){
返回(配料!=null)?配料.stream().map(配料::getPrice)
.reduce(0.0,Double::sum)
: 0;
}
@凌驾
公共字符串toString(){
返回“Pizza[name=“+name+”;cost=“+getTotalCost()+”$”;
}
}
主要

import java.util.ArrayList;
导入java.util.Comparator;
导入java.util.List;
导入java.util.Optional;
公共级素食比萨广场{
公共静态无效检查mostexpensiveveganpizza(列出pizzas){
如果(比萨饼!=null){
可选maxVegan=
pizzas.stream()
.过滤器(比萨饼::isVegan)
.max(Comparator.comparingDouble(Pizza::getTotalCost));
if(maxVegan.isPresent()){
System.out.println(maxVegan.get().toString());
}否则{
System.out.println(“今天菜单上没有纯素比萨饼”);
}
}
}
公共静态void main(字符串[]args){
List pizzas=new ArrayList();
成分番茄=新成分(“番茄”,0.50,假);
成分奶酪=新成分(“奶酪”,0.75,假);
成分西兰花=新成分(“西兰花”,50.00,假);
成分火腿=新成分(“火腿”,10.00,真实);
List INGREDIENTSMARGERITA=新数组列表();
添加(番茄);
添加(奶酪);
披萨玛格丽塔=新披萨(“玛格丽塔”,意为“玛格丽塔”);
List ingredientsSpecial=new ArrayList();
添加特殊成分(番茄);
添加特殊成分(奶酪);
特别添加(西兰花);
比萨特价=新比萨(“特价”,IngCreditsSpecial);
List ingredientsProsciutto=新数组列表();
加入(西红柿);
添加(奶酪);
添加(火腿);
比萨火腿=新比萨(“火腿”,IngreditsProsciutto);
比萨加(玛格丽塔);
比萨饼。添加(特殊);
比萨。加(火腿);
checkmostexpensiveveganpizzas(比萨);
}
}
输出

比萨饼[名称=特殊;成本=51.25美元]

如果您不喜欢干净的代码,可以使用

Optional<Pizza> maxVegan =
                pizzas.stream()
                      .filter(p -> p.getIngredients().stream().noneMatch(Ingredient::isMeat))
                      .reduce((p1, p2) -> p1.getIngredients().stream().map(Ingredient::getPrice).reduce(0.0, Double::sum)
                                        < p2.getIngredients().stream().map(Ingredient::getPrice).reduce(0.0, Double::sum) ? p1 : p2);
可选maxVegan=
pizzas.stream()
.filter(p->p.GetComponents().stream().noneMatch(配料::isMeat))
.reduce((p1,p2)->p1.getComponents().stream().map(component::getPrice)。reduce(0.0,Double::sum)

编辑:使用
reduce
选择最大值比萨饼的表达式基于Urma、Fusco和Mycroft的《Java8在行动》一书中的清单5.8(第110页)。一本好书!:-)

要找到价格最高的比萨饼,您需要在每次比较价格时计算每个比萨饼的价格,或者有一个存储比萨饼和价格的对象

这里有一个解决方案,它使用匿名对象来保存我们需要比萨饼及其价格的临时状态:

Optional<Pizza> pizza = pizzas.stream()

        .filter(p -> p.getIngredients().stream()
                .noneMatch(Ingredient::isMeat)) // filter

        .map(p -> new Object() { // anonymous object to hold (pizza, price)

            Pizza pizza = p; // store pizza

            int price = p.getIngredients().stream()
                    .mapToInt(Ingredient::getPrice).sum(); // store price
        })

        .max(Comparator.comparingInt(o -> o.price)) // find the highest price
        .map(o -> o.pizza); // get the corresponding pizza
Optional pizza=pizzas.stream()
.filter(p->p.getComponents().stream())
.noneMatch(成分::isMeat))//过滤器
.map(p->new Object(){//要保存的匿名对象(比萨饼,价格)
比萨饼=p;//比萨饼店
int price=p.getComponents().stream()
.mapToInt(配料::getPrice).sum();//存储价格
})
.max(Comparator.comparingit(o->o.price))//查找最高价格
.map(o->o.pizza);//得到相应的比萨饼

为什么不在映射后使用
Stream.max
?而不是排序?不。您需要首先将
比萨饼
映射到类似
条目的东西
Optional<Pizza> maxVegan =
                pizzas.stream()
                      .filter(p -> p.getIngredients().stream().noneMatch(Ingredient::isMeat))
                      .reduce((p1, p2) -> p1.getIngredients().stream().map(Ingredient::getPrice).reduce(0.0, Double::sum)
                                        < p2.getIngredients().stream().map(Ingredient::getPrice).reduce(0.0, Double::sum) ? p1 : p2);
Optional<Pizza> pizza = pizzas.stream()

        .filter(p -> p.getIngredients().stream()
                .noneMatch(Ingredient::isMeat)) // filter

        .map(p -> new Object() { // anonymous object to hold (pizza, price)

            Pizza pizza = p; // store pizza

            int price = p.getIngredients().stream()
                    .mapToInt(Ingredient::getPrice).sum(); // store price
        })

        .max(Comparator.comparingInt(o -> o.price)) // find the highest price
        .map(o -> o.pizza); // get the corresponding pizza