如何在嵌套列表上使用 groupingBy
How to use groupingBy on nested lists
我遇到了一个棘手的情况,我必须对具有嵌套列表的对象使用 groupingBy。我用 map()、flatmap()、toMap() 尝试了一些东西,但无法提出解决方案,只能绕圈子。非常感谢来自流专家的任何帮助。我需要在我的 OrdersAnalyzer class 中实现 2 个方法。
这是我的对象的样子:
public class Order {
private final String id;
private final Set<OrderLine> orderLines = new HashSet<>();
private final Customer customer;
//getters, setters, equals, hashcode omitted for brevity
}
public class OrderLine {
private final Product product;
private final Integer quantity;
//getters, setters, equals, hashcode omitted for brevity
}
public class Product {
private final String name;
private final BigDecimal price;
//getters, setters, equals, hashcode omitted for brevity
}
public class OrdersAnalyzer {
/**
* Should return at most three most popular products. Most popular product is the product that have the most occurrences
* in given orders (ignoring product quantity).
* If two products have the same popularity, then products should be ordered by name
*
* @param orders orders stream
* @return list with up to three most popular products
*/
public List<Product> findThreeMostPopularProducts(Stream<Order> orders) {
orders.forEach(order -> {
order.getOrderLines().stream().collect(
Collectors.groupingBy(OrderLine::getProduct, *What to add here?* )
);
});
}
/**
* Should return the most valuable customer, that is the customer that has the highest value of all placed orders.
* If two customers have the same orders value, then any of them should be returned.
*
* @param orders orders stream
* @return Optional of most valuable customer
*/
public Optional<Customer> findMostValuableCustomer(Stream<Order> orders) {
orders.collect(
Collectors.groupingBy(Order::getCustomer, *What to add here?*)
);
}
}
findThreeMostPopularProducts
您要支持的 API 需要您创建产品频率图,以便在找到 top-N
时进行查找。在这种情况下 Collectors.counting()
将是一个很好的 downstream
来利用。
请注意,它会为您提供 Map<Product, Long> productFrequency
作为结果,然后您需要定义自定义 Comparator<Map.Entry<Product, Long>>
以辅助对名称比较进行额外检查。
此外,迭代此映射的条目,同时 sort
ing 和 limit
ing 到 N 个元素将使您更接近您正在寻找的答案。
findMostValuableCustomer
在此 API 中,您要根据客户各自订单中的最高价值来比较客户。所以使用默认的 toList
下游分组就足够了。
它将帮助您 Map<Customer, List<Order>>
,其中您需要从每个客户的所有订单中找到具有 max
价格值的条目。
所以比较器,例如 Comparator.comparing(e -> findHighestValueOrder(e.getValue())
,其中 e.getValue()
是 List<Order> customerOrders
将帮助您解决问题。
我会把 findHighestValueOrder
的实现留给你,因为如果你知道如何 map
和 flatMap
,你只需要找到 max
价格在这些订单中或回退到某些默认值,例如 BigDecimal.ZERO
.
我遇到了一个棘手的情况,我必须对具有嵌套列表的对象使用 groupingBy。我用 map()、flatmap()、toMap() 尝试了一些东西,但无法提出解决方案,只能绕圈子。非常感谢来自流专家的任何帮助。我需要在我的 OrdersAnalyzer class 中实现 2 个方法。 这是我的对象的样子:
public class Order {
private final String id;
private final Set<OrderLine> orderLines = new HashSet<>();
private final Customer customer;
//getters, setters, equals, hashcode omitted for brevity
}
public class OrderLine {
private final Product product;
private final Integer quantity;
//getters, setters, equals, hashcode omitted for brevity
}
public class Product {
private final String name;
private final BigDecimal price;
//getters, setters, equals, hashcode omitted for brevity
}
public class OrdersAnalyzer {
/**
* Should return at most three most popular products. Most popular product is the product that have the most occurrences
* in given orders (ignoring product quantity).
* If two products have the same popularity, then products should be ordered by name
*
* @param orders orders stream
* @return list with up to three most popular products
*/
public List<Product> findThreeMostPopularProducts(Stream<Order> orders) {
orders.forEach(order -> {
order.getOrderLines().stream().collect(
Collectors.groupingBy(OrderLine::getProduct, *What to add here?* )
);
});
}
/**
* Should return the most valuable customer, that is the customer that has the highest value of all placed orders.
* If two customers have the same orders value, then any of them should be returned.
*
* @param orders orders stream
* @return Optional of most valuable customer
*/
public Optional<Customer> findMostValuableCustomer(Stream<Order> orders) {
orders.collect(
Collectors.groupingBy(Order::getCustomer, *What to add here?*)
);
}
}
findThreeMostPopularProducts
您要支持的 API 需要您创建产品频率图,以便在找到 top-N
时进行查找。在这种情况下 Collectors.counting()
将是一个很好的 downstream
来利用。
请注意,它会为您提供 Map<Product, Long> productFrequency
作为结果,然后您需要定义自定义 Comparator<Map.Entry<Product, Long>>
以辅助对名称比较进行额外检查。
此外,迭代此映射的条目,同时 sort
ing 和 limit
ing 到 N 个元素将使您更接近您正在寻找的答案。
findMostValuableCustomer
在此 API 中,您要根据客户各自订单中的最高价值来比较客户。所以使用默认的 toList
下游分组就足够了。
它将帮助您 Map<Customer, List<Order>>
,其中您需要从每个客户的所有订单中找到具有 max
价格值的条目。
所以比较器,例如 Comparator.comparing(e -> findHighestValueOrder(e.getValue())
,其中 e.getValue()
是 List<Order> customerOrders
将帮助您解决问题。
我会把 findHighestValueOrder
的实现留给你,因为如果你知道如何 map
和 flatMap
,你只需要找到 max
价格在这些订单中或回退到某些默认值,例如 BigDecimal.ZERO
.