Группировать по сумме, затем сортировать список объектов транзакций Java - PullRequest
2 голосов
/ 29 июня 2019

У меня есть список транзакций по дням, транзакция содержит следующие атрибуты:

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

Имея список List<Transaction>, я хочу извлечь топ-100 продаваемых товаров по магазинам.

Поэтому мне нужно сгруппировать транзакции по shopId, а затем по productReference, а затем суммировать количества, а не сортировать из числа самых продаваемых в наименьшее.

Спасибо за вашу помощь

Ответы [ 2 ]

1 голос
/ 05 июля 2019

Я бы предложил использовать дополнительный тип Product с переопределенными equals() и hasCode(), который будет состоять только из shopId и productReference . Новый тип будет служить выходом, что сделает всю работу по преобразованию более очевидной. Рассмотрим мою версию с 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());
1 голос
/ 04 июля 2019
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 в качестве ключа и списки транзакций, отсортированные по количеству в качестве значения.Ожидаемое поведение?

...