【问题标题】:Java Stream - Groupby based on child class and calculate sum from parent classJava Stream - 基于子类的Groupby并从父类计算总和
【发布时间】:2021-10-10 04:27:07
【问题描述】:

以下是我的实体:

产品

@Entity
@Table(name = "Product")
public class Product extends ReusableFields
{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    Long productId;

    @NonNull
    @Column(name = "product_name")
    String productName;
    String measurementUnit;
    //more fields and getters setters
}

与产品相关的Inward Outward List:

@Entity
@Table(name = "inward_outward_entries")
public class InwardOutwardList extends ReusableFields
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long entryid;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "productId", nullable = false)
    @JsonIgnoreProperties(
    { "hibernateLazyInitializer", "handler" })
    Product product;
    
    @JsonSerialize(using = DoubleTwoDigitDecimalSerializer.class)
    Double quantity;
    //more fields
}

具有一组内向外向清单的内向库存:

@Entity
@Table(name = "inward_inventory")
public class InwardInventory extends ReusableFields implements Cloneable
{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "inwardid")
    Long inwardid;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "inwardinventory_entry", joinColumns =
    { @JoinColumn(name = "inwardid", referencedColumnName = "inwardid") }, inverseJoinColumns =
    { @JoinColumn(name = "entryId", referencedColumnName = "entryId") })
    Set<InwardOutwardList> inwardOutwardList = new HashSet<>();

    //more fields

}

我有一个内向库存清单,我想根据产品对其进行分组。所以,我想做的是

SUM(InwardInventory.InwardOutwardList.quantity) 同时基于 InwardInventory.InwardOutwardList.Product.productName 和 InwardInventory.InwardOutwardList.Product.measurementUnit 进行分组

我是流的新手,我知道可以做到但无法获得确切的解决方案。有人可以提供指导或帮助吗?

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    据我了解,您需要一个 Map,其中键是唯一的 productNamemeasurementUnit 的某种表示,值是 Double。

    首先,您需要定义将用作地图键的类。它的要求是仅基于productNamemeasurementUnit 字段实现equals 和hashCode。否则,您将无法将数量正确聚合到地图中。如果您关注Vlad Mihalcea's advice,那么您不能使用Product 类作为键,因为它仅基于id 字段实现equals 和hashCode。在下面的示例中,Pair&lt;L, R&gt; 已根据 LR 字段正确实现了 equals 和 hashCode。

    List<InwardInventory> inwardInventoryList = ...;
    
    Map<Pair<String, String>, Double> map = inwardInventoryList.stream()
            .flatMap(i -> i.getInwardOutwardList().stream())
            .collect(Collectors.toMap(l -> Pair.of(l.getProduct().getProductName(), l.getProduct().getMeasurementUnit()),
                    InwardOutwardList::getQuantity,
                    Double::sum));
    

    第一个操作是flatMap,因为每个InwardInventory 都有一个Set&lt;InwardOutwardList&gt;,但我们想要一个InwardOutwardList 对象流。

    第二个操作是Collectors.toMap定义的here

    【讨论】:

    • 谢谢@Dan。这行得通。我稍微调整了一下以转换为对象而不是地图。但逻辑奏效了。
    【解决方案2】:

    我从您的代码中创建了简单的类,因为不需要注释。

    班级Product

    public class Product {
        private Long  productId;
        private String  measurementUnit;
        private String  productName;
    
        public Product(Long productId, String measurementUnit, String productName) {
            this.productId = productId;
            this.measurementUnit = measurementUnit;
            this.productName = productName;
        }
    
        public Long getProductId() {
            return productId;
        }
    
        public String getMeasurementUnit() {
            return measurementUnit;
        }
    
        public String getProductName() {
            return productName;
        }
    }
    

    班级InwardOutwardList

    public class InwardOutwardList {
        private Long  entryid;
        private Product  product;
        private Double quantity;
    
        public InwardOutwardList(Long entryid, Product product, Double quantity) {
            this.entryid = entryid;
            this.product = product;
            this.quantity = quantity;
        }
    
        public Long getEntryid() {
            return entryid;
        }
    
        public Product getProduct() {
            return product;
        }
    
        public Double getQuantity() {
            return quantity;
        }
    }
    

    最后,类 InwardInventory 包含方法 main,该方法演示了如何使用流 API 来实现所需的结果。
    (代码后的注释。)

    import java.util.DoubleSummaryStatistics;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    public class InwardInventory {
        private Long  inwardid;
        private Set<InwardOutwardList>  inwardOutwardList = new HashSet<>();
    
        public InwardInventory(Long id) {
            inwardid = id;
        }
    
        public static void main(String[] args) {
            Product p1 = new Product(1L, "unit", "Product_1");
            Product p2 = new Product(1L, "unit", "Product_1");
            InwardOutwardList ioLst = new InwardOutwardList(1L, p1, 1D);
            InwardOutwardList ioLst2 = new InwardOutwardList(2L, p2, 2D);
            InwardInventory ii = new InwardInventory(1L);
            ii.inwardOutwardList.add(ioLst);
            ii.inwardOutwardList.add(ioLst2);
            Map<String, DoubleSummaryStatistics> map = ii.inwardOutwardList.stream()
                                                         .collect(Collectors.groupingBy(iol -> iol.getProduct().getProductName(),
                                                                                        Collectors.summarizingDouble(InwardOutwardList::getQuantity)));
            map.forEach((p, s) -> System.out.println(p + " = " + s.getSum()));
        }
    }
    
    • ii.inwardOutwardList.stream() 创建一个Stream,其中该流中的每个元素都是InwardOutwardList 的一个实例。
    • collect 方法有一个类型为 Collector 的参数。
    • Collectors 类是一个实用程序类,其中包含返回特殊类型收集器的方法。
    • collect 方法返回一个 Map,其中映射键是产品名称 - 从类 Product 中提取,映射值是类 DoubleSummaryStatistics 的一个实例。
    • 方法getSum,在类DoubleSummaryStatistics 中返回数量的总和。

    运行上面的代码会产生以下结果:

    Product_1 = 3.0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-17
      • 1970-01-01
      • 2012-10-21
      • 1970-01-01
      相关资源
      最近更新 更多