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

问题描述 投票:3回答:3

我只是试着理解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);

此代码返回未分类的比萨饼值。

java java-8 java-stream
3个回答
5
投票
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"));
    }
}

如果你想让Ingredient.getPrice()返回double,你可以在Stream.mapToDouble()中使用Pizza.price(),在Comparator.comparingDouble()中使用Pizza.mostExpensiveVegetarianPizza()


4
投票

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

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

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

3
投票

我做了一个简短的功能实例。我已经在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;
}

}

比萨

public class Pizza {

private String name;
private List<Ingredient> ingredients;

public Pizza(String name, List<Ingredient> ingredients) {
    this.name = name;
    this.ingredients = ingredients;
}

public String getName() {
    return name;
}

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


public List<Ingredient> getIngredients() {
    return ingredients;
}


public void setIngredients(List<Ingredient> ingredients) {
    this.ingredients = ingredients;
}

public boolean isVegan() {
    return  (ingredients != null) ? ingredients.stream().noneMatch(Ingredient::isMeat)
                                  : false;
}

public double getTotalCost() {
    return  (ingredients != null) ? ingredients.stream().map(Ingredient::getPrice)
                                                        .reduce(0.0, Double::sum)
                                  : 0;
}

@Override
public String toString() {
    return "Pizza [name=" + name + "; cost=" + getTotalCost() +"$]";
}
}

主要

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

public class VeganPizzaPlace {

public static void checkMostExpensiveVeganPizza(List<Pizza> pizzas) {
    if (pizzas != null) {

        Optional<Pizza> maxVegan =
                pizzas.stream()
                      .filter(Pizza::isVegan)
                      .max(Comparator.comparingDouble(Pizza::getTotalCost));

        if (maxVegan.isPresent()) {
            System.out.println(maxVegan.get().toString());
        } else {
            System.out.println("No vegan pizzas in the menu today");
        }
    }
}

public static void main (String[] args) {
    List<Pizza> pizzas = new ArrayList<Pizza>();

    Ingredient tomato   = new Ingredient("tomato", 0.50, false);
    Ingredient cheese   = new Ingredient("cheese", 0.75, false);
    Ingredient broccoli = new Ingredient("broccoli", 50.00, false);
    Ingredient ham      = new Ingredient("ham", 10.00, true);

    List<Ingredient> ingredientsMargherita = new ArrayList<Ingredient>();
    ingredientsMargherita.add(tomato);
    ingredientsMargherita.add(cheese);

    Pizza margherita = new Pizza("margherita", ingredientsMargherita);

    List<Ingredient> ingredientsSpecial = new ArrayList<Ingredient>();
    ingredientsSpecial.add(tomato);
    ingredientsSpecial.add(cheese);
    ingredientsSpecial.add(broccoli);

    Pizza special = new Pizza("special", ingredientsSpecial);

    List<Ingredient> ingredientsProsciutto = new ArrayList<Ingredient>();
    ingredientsProsciutto.add(tomato);
    ingredientsProsciutto.add(cheese);
    ingredientsProsciutto.add(ham);

    Pizza prosciutto = new Pizza("prosciutto", ingredientsProsciutto);

    pizzas.add(margherita);
    pizzas.add(special);
    pizzas.add(prosciutto);

    checkMostExpensiveVeganPizza(pizzas);
}
}

OUTPUT

披萨[name = special;成本= 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);

编辑:使用reduce选择最大值披萨的表达式基于Urma,Fusco和Mycroft出版的“Java 8 in action”一书中的5.8(第110页)。一本好书! :-)

© www.soinside.com 2019 - 2024. All rights reserved.