我有List
个价格和价格组。
static class PriceGroup {
String priceName;
String priceGroup;
}
static class Price {
String priceName;
Integer price;
}
下面是一些示例数据,我编写了一个实现,以找到每个PriceGroup的最低Price。有什么建议我可以重构它以利用流来加入这些数据吗?
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
答案 0 :(得分:2)
要加入2个列表,您可以考虑创建专用对象:
class Joined {
String priceGroup;
String priceName;
Integer price;
...
然后,您可以使用flatMap
在priceGroups
字段上将prices
联接到priceName
并按priceGroup
分组:
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
答案 1 :(得分: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 :(得分: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)));
}