比较 Stream 中的元素

Comparing elements within Stream

假设我有一个项目列表,我使用 Stream 将它转换为另一种类型的列表。还假设原始 itemList 是从数据库中检索的,并按最后更新的时间戳排序,我想保留排序。 (这样就无法对 Stream 进行排序)。我想找出这些元素中的最高价格,如果是,则在 ItemResponse 中设置 isMax 指示器。如果我想使用相同的 Stream 执行此操作,该怎么做?

我想到的一种方法是创建另一个流来比较它,但是,这似乎是重复的工作(在相同的元素上循环两次)。

还是在这种情况下不使用 Stream 并将原始 Stream 转换回 for 循环更好?

List<Item> itemList = Arrays.asList(
                    new Item(BigDecimal.valueOf(10), 1),
                    new Item(BigDecimal.valueOf(20), 2));

List<ItemResponse> itemResponseList = itemList.stream()
                        .map(item -> {
                            ItemResponse itemResponse = new ItemResponse();
                            itemResponse.setId(item.getId());
                            itemResponse.setPrice(item.getAmount());
//adding logic to find the max and set the max indicator, but how ?
        
                            return itemResponse;
                        })
                        .collect(Collectors.toList());
    

//attempt 1 - it works, but it loops the same elements again
Optional<ItemResponse> max = itemResponseList.stream()
                            .collect(Collectors.maxBy(Comparator.comparingDouble(itemResponse -> itemResponse.getPrice().doubleValue())));
                    max.ifPresent(e -> e.setMax(true));


public class Item {

    private BigDecimal amount;
    private int id;

    Item(BigDecimal amount, int id) {
        this.amount = amount;
        this.id = id;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class ItemResponse {

    private BigDecimal price;
    private Boolean isMax;
    private int id;

    ItemResponse() {};

    public Boolean getMax() {
        return isMax;
    }

    public void setMax(Boolean max) {
        isMax = max;
    }

    public BigDecimal getPrice() {
        return price;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "id: " + id + ", price: " + price + ", isMax: " + isMax;
    }
}

您可以制作一个降序排序的列表并只更新列表的头部。

List<Item> itemList = Arrays.asList(
                    new Item(BigDecimal.valueOf(10), 1),
                    new Item(BigDecimal.valueOf(20), 2));

List<ItemResponse> itemResponseList = itemList.stream()
                        .map(item -> {
                            ItemResponse itemResponse = new ItemResponse();
                            itemResponse.setId(item.getId());
                            itemResponse.setPrice(item.getAmount());
                            return itemResponse;
                        })
                        // reverse sorting
                        .sorted(Comaparator.comparing(ItemResponse::getPrice).reversed())
                        .collect(Collectors.toList());

// only first will be updated, if the list is non-empty
itemResponseList.stream().findFirst().ifPresent(e -> e.setMax(true));

假设在一般情况下多个项目可能有最高 and/or 最低价格,看来流方法无助于避免重复迭代。相反,应该使用循环将项目转换为项目响应,并构建两个具有最高/最低价格的中间项目列表,然后迭代较小的列表并设置适当的指标。

List<ItemResponse> itemResponseList = new ArrayList<>();
List<ItemResponse> maxPriced = new ArrayList<>();
List<ItemResponse> minPriced = new ArrayList<>();

BigDecimal minPrice = null;
BigDecimal maxPrice = null;

for (Item item : itemList) {
    ItemResponse ir = new ItemResponse();
    ir.setId(item.getId());
    ir.setPrice(item.getAmount());
    if (null == minPrice || minPrice.compareTo(ir.getPrice()) >= 0) {
        if (null == minPrice || minPrice.compareTo(ir.getPrice()) > 0) {
            minPrice = ir.getPrice();
            minPriced.clear();
        }
        minPriced.add(ir);
    }
    if (null == maxPrice || maxPrice.compareTo(ir.getPrice()) <= 0) {
        if (null == maxPrice || maxPrice.compareTo(ir.getPrice()) < 0) {
            maxPrice = ir.getPrice();
            maxPriced.clear();
        }
        maxPriced.add(ir);
    }
    itemResponseList.add(ir);
}
minPriced.forEach(i -> i.setMin(true));
maxPriced.forEach(i -> i.setMax(true));

或者,最好只准备 运行 数据库查询以获取 max/min 价格,然后使用这些值在 one 流中设置指标.

BigDecimal[] minMax = getMinMaxPrices(); // {min. max}

List<ItemResponse> itemResponseList = itemList
    .stream()
    .map(item -> {
        ItemResponse itemResponse = new ItemResponse();
        itemResponse.setId(item.getId());
        itemResponse.setPrice(item.getAmount());
        itemResponse.setMin(item.getAmount().equals(minMax[0]));
        itemResponse.setMax(item.getAmount().equals(minMax[1]));
        return itemResponse;
    })
    .collect(Collectors.toList());