java 8 groupby несколько атрибутов - PullRequest
0 голосов
/ 28 июня 2018

У меня есть список элементов коллекций, как показано ниже. Я хотел сгруппировать несколько полей, таких как productCode, а затем для типа productpurchase.

class Product{
    private String productCode;
    // this is ENUM with 2 possible values "ONLINE" or "INSTORE"
    private String productPurchaseType; 
    private String productCost;
    ...
}

Возможный вывод должен быть как

ROW1::ProductCode1, Count of ONLINE,Count of INSTORE,Min, Max
ROW2::ProductCode2, Count of ONLINE,Count of INSTORE, Min, Max

Я использовал приведенный ниже фрагмент кода, но он не дает счет ONLINE и INSTORE

void groupByMerchantMCCCodeZIP(List<Product> productList) {
    Map<String, Map<String, List<Product>>> output = transactionDataList.stream()
        .collect(Collectors.groupingBy(Product::getProductCode,
            Collectors.groupingBy(Product::productPurchaseType)));
    System.out.println(output);
}

Может ли кто-нибудь, кто работал над java 8 groupby, сообщить мне лучший способ сделать это?

Спасибо!

1 Ответ

0 голосов
/ 28 июня 2018

Чтобы объединить несколько значений, вы должны написать свой Collector, для лучшей производительности.

Самый простой способ написать Collector - это вызвать метод Collector.of() в сочетании с классом сборщика результатов. Ниже приведен пример.

Во-первых, я переопределил Product, чтобы улучшить типы полей:

class Product {
    public enum PurchaseType { ONLINE, INSTORE }

    private final String       code;
    private final PurchaseType purchaseType; 
    private final BigDecimal   cost;

    public Product(String code, PurchaseType purchaseType, String cost) {
        this.code = code;
        this.purchaseType = purchaseType;
        this.cost = new BigDecimal(cost);
    }
    public String getCode() {
        return this.code;
    }
    public PurchaseType getPurchaseType() {
        return this.purchaseType;
    }
    public BigDecimal getCost() {
        return this.cost;
    }
}

Тогда класс коллектора результатов:

class ProductResult {
    private int        onlineCount;
    private int        instoreCount;
    private BigDecimal minCost;
    private BigDecimal maxCost;

    public void add(Product product) {
        if (product.getPurchaseType() == Product.PurchaseType.ONLINE)
            this.onlineCount++;
        else if (product.getPurchaseType() == Product.PurchaseType.INSTORE)
            this.instoreCount++;
        if (this.minCost == null || product.getCost().compareTo(this.minCost) < 0)
            this.minCost = product.getCost();
        if (this.maxCost == null || product.getCost().compareTo(this.maxCost) > 0)
            this.maxCost = product.getCost();
    }
    public ProductResult merge(ProductResult that) {
        this.onlineCount += that.onlineCount;
        this.instoreCount += that.instoreCount;
        if (this.minCost == null || that.minCost.compareTo(this.minCost) < 0)
            this.minCost = that.minCost;
        if (this.maxCost == null || that.maxCost.compareTo(this.maxCost) > 0)
            this.maxCost = that.maxCost;
        return this;
    }
    @Override
    public String toString() {
        return "[online: " + this.onlineCount +
              ", instore: " + this.instoreCount +
              ", min: " + this.minCost +
              ", max: " + this.maxCost + "]";
    }
    public int getOnlineCount() {
        return this.onlineCount;
    }
    public int getInstoreCount() {
        return this.instoreCount;
    }
    public BigDecimal getMinCost() {
        return this.minCost;
    }
    public BigDecimal getMaxCost() {
        return this.maxCost;
    }
}

Демо

List<Product> productList = Arrays.asList(
        new Product("MILK", Product.PurchaseType.ONLINE, "3.99"),
        new Product("MILK", Product.PurchaseType.ONLINE, "3.99"),
        new Product("MILK", Product.PurchaseType.INSTORE, "4.95"),
        new Product("BREAD", Product.PurchaseType.INSTORE, "7.48")
);

Map<String, ProductResult> result = productList.stream()
        .collect(Collectors.groupingBy(Product::getCode,
                    Collector.of(ProductResult::new,
                                 ProductResult::add,
                                 ProductResult::merge,
                                 Characteristics.UNORDERED)));
result.entrySet().forEach(System.out::println);

выход

BREAD=[online: 0, instore: 1, min: 7.48, max: 7.48]
MILK=[online: 2, instore: 1, min: 3.99, max: 4.95]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...