如何使用流和1. 8函数连接2个列表?

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

我有一个价格和价格组的List

static class PriceGroup {
    String priceName;
    String priceGroup;
}

static class Price {
    String priceName;
    Integer price;
}

下面是一些示例数据,我写的一个实现找到了每个PriceGroup的最低价格。有什么建议我如何重构这个来利用流来加入这些数据?

List<PriceGroup> priceGroups = Arrays.asList(
        new PriceGroup("F1", "Friends"),
        new PriceGroup("F2", "Friends"),
        new PriceGroup("O1", "Others"),
        new PriceGroup("O2", "Others"));

List<Price> prices = Arrays.asList(
        new Price("F1", 100),
        new Price("F2", 150),
        new Price("O1", 250),
        new Price("O2", 300));

public Map<String, Integer> getBestPrices(List<PriceGroup> priceGroups, List<Price> prices) 
{
    Map<String, Integer> bestPrice = new HashMap<String, Integer>(); 
    for (PriceGroup priceGroup : priceGroups) {
        if (bestPrice.get(priceGroup.priceGroup) == null) {
            bestPrice.put(priceGroup.priceGroup, 10000000);
        }

        for (Price price : prices) {
            if (price.priceName.equals(priceGroup.priceName)) {
                bestPrice.put(priceGroup.priceGroup, Math.min(price.price, bestPrice.get(priceGroup.priceGroup)));
            }
        }
    }

    return bestPrice;
}

对于给定的数据,我的函数应该返回一个映射:

F1 => 100 O1 => 250

java java-8 java-stream
3个回答
2
投票

要获得加入的2个列表,您可以考虑创建专用对象:

class Joined {
    String priceGroup;
    String priceName;
    Integer price;
    ...

然后,使用flatMap你可以加入priceGroupsprices场上的priceNamepriceGroup组:

Map<String, Optional<Joined>> map = priceGroups.stream()
        .flatMap(group -> prices.stream()
                .filter(p -> p.getPriceName().equals(group.getPriceName()))
                .map(p -> new Joined(group.getPriceGroup(), group.getPriceName(), p.getPrice())))
        .collect(groupingBy(Joined::getPriceGroup, minBy(Comparator.comparing(Joined::getPrice))));

现在从地图获取值可以打印预期结果:

for (Optional<Joined> value : map.values()) {
        value.ifPresent(joined -> System.out.println(joined.getPriceName() + " " + joined.getPrice()));
    }

// O1 250
// F1 100

2
投票

第一:我认为@Ruslan的答案是你应该使用的。

但你提到返回必须是Map<String, Integer>并且字符串应该是F1而不是Friends。所以我试着一气呵成,让这个功能憎恶:

public static Map<String, Integer> getBestPricesV2(List<PriceGroup> priceGroups, List<Price> prices) {
    final String unknownPriceName = "Unkown price name";

    return prices.stream().collect(Collectors.groupingBy(
            // map the price name the priceGroup name
            price -> priceGroups.stream()
                    .filter(priceGroup -> priceGroup.getPriceName().equals(price.getPriceName()))
                    .findFirst()
                    .map(PriceGroup::getPriceGroup)
                    .orElse(unknownPriceName), 
            Collectors.minBy(Comparator.comparing(Price::getPrice))))
        .entrySet()
        .stream()
        // extract the Optional<Price> to the price value
        .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElse(new Price(unknownPriceName, -1)).getPrice()));
}

2
投票

您可以简单地避免使用连接类进行此操作,并将其执行为:

public Map<String, Integer> getBestPrices(List<PriceGroup> priceGroups, List<Price> prices) {
// create a map of priceName to minimum price value using list of prices
    Map<String, Integer> minPrice = prices.stream()
            .collect(Collectors.groupingBy(Price::getPriceName,
                    Collectors.reducing(0, Price::getPrice,
                            BinaryOperator.minBy(Comparator.naturalOrder()))));

// use the map above to fill in the best prices map with values present or default
    return priceGroups.stream()
            .collect(Collectors.toMap(PriceGroup::getPriceGroup,
                    priceGroup ->
                            minPrice.getOrDefault(priceGroup.getPriceName(), 10000000)));
}
© www.soinside.com 2019 - 2024. All rights reserved.