【问题标题】:Group by, sum then sort a list of transaction objects java分组,求和然后对事务对象列表进行排序java
【发布时间】:2019-06-29 14:36:10
【问题描述】:

我有一个按天计算的交易列表,该交易包含以下属性:

Transaction(int transactionID,
                       DateTime transactionDate,
                       String shopId,
                       int productReference,
                       int quantity,
                       float price);

有一个列表List<Transaction>,我想按商店提取前 100 名销售的产品。

所以我需要先按 shopId 再按 productReference 对交易进行分组,然后对数量求和,而不是从最畅销到最少排序。

感谢您的帮助

【问题讨论】:

    标签: list sorting java-8 group-by


    【解决方案1】:
    private static Collector<Transaction, ?, List<Transaction>> limit(int limit) {
        return Collector.of(
                ArrayList::new,
                (list, transaction) -> { if (list.size() < limit) list.add(transaction); },
                (list1, list2) -> {
                    list1.addAll(list2.subList(0, Math.min(list2.size(), Math.max(0, limit - list1.size()))));
                    return list1;
                }
        );
    }
    
    
    
      public static void main(String[] args) {
            Map<String, List<Transaction>> groupedMap = listOfTransactions
                    .stream()
                    .sorted((t1, t2) -> Integer.compare(t2.getQuantity(), t1.getQuantity()))
                    .collect(
                    Collectors.groupingBy(
                            Transaction::getShopId,
                            limit(100)
                    )
            );
        }
    

    因此,您将获得一个以 shopId 为键的地图,以及按数量排序的交易列表作为值。 这是预期的行为吗?

    【讨论】:

      【解决方案2】:

      我建议使用额外的 Product 类型,覆盖 equals()hasCode(),这将仅包含 shopId产品参考。新类型将作为输出,这将使所有转换工作更加明显。考虑我的版本,使用 Lombok lib

      import lombok.*;
      
      @Data
      @RequiredArgsConstructor(staticName = "of")
      @ToString
      public class Product {
      
          final String shopId;
          final int productReference;
      }
      

      以及函数代码本身:

          List<Product> products = transactions.stream()
                  // grouping transactions by the same product
                  .collect(Collectors.groupingBy(transaction -> Product.of(
                          transaction.getShopId(),
                          transaction.getProductReference())))
                  .entrySet().stream()
                  // summing all price * quantity occurrences to find top sellings
                  .collect(Collectors.toMap(
                          Map.Entry::getKey,
                          e -> e.getValue().stream()
                                  .mapToDouble(p -> p.getQuantity() * p.getPrice())
                                  .sum()))
                  .entrySet().stream()
                  // sorting by the most expensive ones at the top, 
                  // limiting to 10 and collecting to the list 
                  .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                  .map(Map.Entry::getKey)
                  .limit(10)
                  .collect(Collectors.toList());
      

      【讨论】:

        猜你喜欢
        • 2020-12-29
        • 1970-01-01
        • 1970-01-01
        • 2018-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多