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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了具有公共多个字段的对象列表中的java 8 sum字段相关的知识,希望对你有一定的参考价值。

我有这个对象列表

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
  }
]

你能帮帮我们吗?

答案

这是一种可能性:使用复合键立即分组:

.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!

以上是关于具有公共多个字段的对象列表中的java 8 sum字段的主要内容,如果未能解决你的问题,请参考以下文章

检查自定义对象列表是不是与 Java 8 中的属性具有相同的值

具有重复键的对象列表将字段组合到逗号列表中

面向对象函数基本知识理论篇

面向对象编程私有类字段+get/set还是公共类字段?

Java 8 Stream 按键过滤对象列表。排除列表中的键并获取字符串

具有任何匹配属性的对象的 JAVA 8 过滤器列表