带有多个公共字段的对象列表中的java 8 sum字段

时间:2019-03-05 07:39:35

标签: java java-8 lombok

我有这个对象列表

List<DetailDto> details;
    @Value
    public class DetailDto implements Serializable {
        String category1;
        Integer category2;
        Integer price;

        transient Integer totalPrice;
    }

带有此列表

[
  {
    "category1": "ABC",
    "category2": 30,
    "price": 195,
    "totalPrice": null
  },
  {
    "category1": "ABC",
    "category2": 30,
    "price": 195,
    "totalPrice": null
  },
  {
    "category1": "ABC",
    "category2": 30,
    "price": 195,
    "totalPrice": null
  },
  {
    "category1": "ABC",
    "category2": 30,
    "price": 390,
    "totalPrice": null
  },
  {
    "category1": "ABC",
    "category2": 30,
    "price": 390,
    "totalPrice": null
  },
  {
    "category1": "DEF",
    "category2": 30,
    "price": 455,
    "totalPrice": null
  },
  {
    "category1": "DEF",
    "category2": 30,
    "price": 455,
    "totalPrice": null
  },
  {
    "category1": "DEF",
    "category2": 30,
    "price": 455,
    "totalPrice": null
  },
  {
    "category1": "DEF",
    "category2": 30,
    "price": 455,
    "totalPrice": null
  },
  {
    "category1": "GHI",
    "category2": 1,
    "price": 18000,
    "totalPrice": null
  }
]

我想通过将List<DetailDto>字段汇总到条件为price的字段中来制作另一个totalPrice对象:

  • 字符串category1很常见
  • 整数category2很常见
  • 整数price很常见

这时我有这个

List<List<DetailDto>> summarizedList = detail().stream()
        .collect(Collectors.groupingBy(DetailDto::category1,
                                       Collectors.groupingBy(DetailDto::category2,
                                                             Collectors.groupingBy(DetailDto::price))))
        .values()
        .stream()
        .flatMap(c1 -> c1.values().stream())
        .flatMap(c2 -> c2.values().stream())
        .collect(Collectors.toList());

返回我List<List<DetailDto>>

我不知道怎么做,尝试之后

summarizedList.stream().map(dto -> dto.stream().reduce((x,y) -> new DetailDto(x.productCode(), x.productQt(), x.orderPrice(), Integer.sum(x.orderPrice(), y.orderPrice()).orElse(null).collect(Collectors.toList());

它将返回

[
  {
    "category1": "ABC",
    "category2": 30,
    "price": 195,
    "totalPrice": 390
  },
  {
    "category1": "ABC",
    "category2": 30,
    "price": 390,
    "totalPrice": 780
  },
  {
    "category1": "DEF",
    "category2": 30,
    "price": 455,
    "totalPrice": 910
  },
  {
    "category1": "GHI",
    "category2": 1,
    "price": 18000,
    "totalPrice": null
  }
]

我真正需要的是

[
  {
    "category1": "ABC",
    "category2": 30,
    "price": 195,
    "totalPrice": 585
  },
  {
    "category1": "ABC",
    "category2": 30,
    "price": 390,
    "totalPrice": 780
  },
  {
    "category1": "DEF",
    "category2": 30,
    "price": 455,
    "totalPrice": 1820
  },
  {
    "category1": "GHI",
    "category2": 1,
    "price": 18000,
    "totalPrice": 18000
  }
]

你能帮我吗?

1 个答案:

答案 0 :(得分:1)

有一种可能性:一次使用组合键进行分组:

.collect(Collectors.groupingBy(DetailDto::key, Collectors.summarizingInt(DetailDto::getPrice)))

请参阅DetailDto.java中Key的定义(并注意其eclipse生成的hashCodeequals方法):

import java.io.Serializable;

@SuppressWarnings("serial")
public class DetailDto implements Serializable {
    String category1;
    Integer category2;
    Integer price;

    transient Integer totalPrice;

    public DetailDto() {
    }



    public DetailDto(String category1, Integer category2, Integer price, Integer totalPrice) {
        super();
        this.category1 = category1;
        this.category2 = category2;
        this.price = price;
        this.totalPrice = totalPrice;
    }



    public String getCategory1() {
        return category1;
    }

    public void setCategory1(String category1) {
        this.category1 = category1;
    }

    public Integer getCategory2() {
        return category2;
    }

    public void setCategory2(Integer category2) {
        this.category2 = category2;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public Integer getTotalPrice() {
        return totalPrice;
    }

    public void setTotalPrice(Integer totalPrice) {
        this.totalPrice = totalPrice;
    }

    Key key() {
        return new Key(category1, category2, price);
    }

}
class Key {
    String category1;
    Integer category2;
    Integer price;

    public Key(String category1, Integer category2, Integer price) {
        super();
        this.category1 = category1;
        this.category2 = category2;
        this.price = price;
    }
    public String getCategory1() {
        return category1;
    }
    public Integer getCategory2() {
        return category2;
    }
    public Integer getPrice() {
        return price;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((category1 == null) ? 0 : category1.hashCode());
        result = prime * result + ((category2 == null) ? 0 : category2.hashCode());
        result = prime * result + ((price == null) ? 0 : price.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Key other = (Key) obj;
        if (category1 == null) {
            if (other.category1 != null)
                return false;
        } else if (!category1.equals(other.category1))
            return false;
        if (category2 == null) {
            if (other.category2 != null)
                return false;
        } else if (!category2.equals(other.category2))
            return false;
        if (price == null) {
            if (other.price != null)
                return false;
        } else if (!price.equals(other.price))
            return false;
        return true;
    }
}

Main.java

import java.io.IOException;
import java.util.IntSummaryStatistics;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;

public class Main {

    public static void main(String[] args) throws IOException {
        DetailDto[] values = new ObjectMapper().readerFor(DetailDto[].class)
                .readValue(Main.class.getResourceAsStream("data.json"));
//      for (DetailDto dto : values) {
//          display(dto);
//      }

        Map<Key, IntSummaryStatistics> res = Stream.of(values)
                .collect(Collectors.groupingBy(DetailDto::key, Collectors.summarizingInt(DetailDto::getPrice)));

        Stream<DetailDto> agg = res.entrySet().stream().map(e -> new DetailDto(e.getKey().category1,
                e.getKey().category2, e.getKey().price, (int) e.getValue().getSum()));

        agg.forEach(Main::display);

    }

    protected static void display(DetailDto dto) {
        final ObjectWriter json = new ObjectMapper().writerFor(DetailDto.class).withDefaultPrettyPrinter();
        try {
            System.out.println(json.writeValueAsString(dto));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}

HTH!