更好的方法进行流和?

发布于 2025-02-08 03:37:22 字数 766 浏览 1 评论 0原文

我有一个对象

public class Sample {
   private String Id;
   ...
   private String acct;
   private BigDecimal amt1;
   private BigDecimal amt3;
}

,我想从列表

Id | acct  |  amt1   |  amt2   
1  |  1111  |  0.50   |  0.50 
2  |  1112  |  0.50   |  0.50 

中总结AMT1和AMT2的

Map<Object, Sample> map = collectedTxs.stream()
        .collect(Collectors.toMap(
            f -> f.getAcct(),
            Function.identity(),
            (s, a) -> new Sample(
                s.getId(),
                s.getAcct(),
                s.getAmt1().add(a.getAmt1()),
                s.getAmt2().add(a.getAmt2()),
            ), LinkedHashMap::new));

列表有什么更好的方法吗?我不想将结果重新分配到另一个示例对象。

I have an object

public class Sample {
   private String Id;
   ...
   private String acct;
   private BigDecimal amt1;
   private BigDecimal amt3;
}

I have a list

Id | acct  |  amt1   |  amt2   
1  |  1111  |  0.50   |  0.50 
2  |  1112  |  0.50   |  0.50 

I want to sum amt1 and amt2 from a list

Map<Object, Sample> map = collectedTxs.stream()
        .collect(Collectors.toMap(
            f -> f.getAcct(),
            Function.identity(),
            (s, a) -> new Sample(
                s.getId(),
                s.getAcct(),
                s.getAmt1().add(a.getAmt1()),
                s.getAmt2().add(a.getAmt2()),
            ), LinkedHashMap::new));

Is there any better way to do it? I don't want to reassign the result to another Sample object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黯淡〆 2025-02-15 03:37:22

我不想将结果重新分配到另一个示例对象。

流旨在用于映射值。不建议在流环境外修改现有状态,因为它可能在某些情况下导致数据不一致。但是,您仍然可以使用Java 8+地图功能非常有效地做到这一点。 (流并不总是操纵数据的最佳或最有效的方法。使用循环没有错。)

这是我的做法。这是唯一更改的班级定义。

  • 静态副本方法返回复制实例(根据 mcemperor )。
  • 添加值并返回当前实例的添加方法。
static class Sample {
    private String Id;
    private String acct;
    private BigDecimal amt1;
    private BigDecimal amt2;
    public Sample(String id, String acct, BigDecimal amt1,
            BigDecimal amt2) {
        Id = id;
        this.acct = acct;
        this.amt1 = amt1;
        this.amt2 = amt2;   
    }
    
    public Sample(Sample sample) {
        this(sample.Id, sample.acct,sample.amt1,sample.amt2);
    }
    
    public static Sample copyOf(Sample s) {
        return new Sample(s.Id, s.acct, s.amt1,s.amt2);
    }
    
    public Sample add(Sample sample) {
        amt1 = amt1.add(sample.amt1);
        amt2 = amt2.add(sample.amt2);
        return this;
    }
    // other getters and setters
    public void setId(String id) {
        Id = id;
    }
    
    public void setAcct(String acct) {
        this.acct = acct;
    }
    
    public void setAmt1(BigDecimal amt1) {
        this.amt1 = amt1;
    }
    
    public void setAmt2(BigDecimal amt2) {
        this.amt2 = amt2;
    }
    
    public String getId() {
        return Id;
    }
    
    public String getAcct() {
        return acct;
    }
    
    public BigDecimal getAmt1() {
        return amt1;
    }
    
    public BigDecimal getAmt2() {
        return amt2;
    }

    @Override
    public String toString() {
        return String.format("[%s, %s, %s, %s]", Id, acct, amt1,
                amt2);
    }
    
}

数据

List<Sample> collectedTxs = List.of(
        new Sample("1", "1111", new BigDecimal(".50"),
                new BigDecimal(".50")),
        new Sample("2", "1112", new BigDecimal(".50"),
                new BigDecimal(".50")),
        new Sample("2", "1112", new BigDecimal("1.50"),
                new BigDecimal("2.50")),
        new Sample("1", "1111", new BigDecimal("4.50"),
                new BigDecimal("8.50")));

流程

  • 在帐户列表上迭代。
  • 并使用合并方法结合相同的帐户。
  • ACCT是密钥
  • s是每个帐户的第一个遇到的实例。
  • 双方函数通过添加使用方法参考
Map<String,Sample> map = new HashMap<>();
for (Sample s : collectedTxs) {
    map.merge(s.getAcct(), s, Sample::add);
}


map.forEach((k,v)-> System.out.println(k + " " + v);

prints

1112 [2, 1112, 2.00, 3.00]
1111 [1, 1111, 5.00, 9.00]

将它们结合在一起,这是原始数据。请注意,迭代中遇到的第一个帐户已更改。

collectedTxs.forEach(System.out::println);

[1, 1111, 5.00, 9.00]
[2, 1112, 2.00, 3.00]
[2, 1112, 1.50, 2.50]
[1, 1111, 4.50, 8.50]

如果您想保留原始实例。然后在地图构造中进行以下更改。

map.merge(s.getAcct(),  Sample.copyOf(s), Sample::add);

I don't want to reassign the result to another Sample object.

Streams are meant to be used to map values. Modifying existing state outside of the stream environment is ill advised as it can cause data inconsistencies in certain situations. But you can still do it very efficiently using Java 8+ map features. (Streams is not always the best or most efficient way of manipulating data. There is nothing wrong with using loops.)

Here is how I would do it. Here is the class definition with the only changes being.

  • a static copy method that returns a copied instance (Per suggestion by M.C.Emperor).
  • an add method that adds the values and returns the current instance.
static class Sample {
    private String Id;
    private String acct;
    private BigDecimal amt1;
    private BigDecimal amt2;
    public Sample(String id, String acct, BigDecimal amt1,
            BigDecimal amt2) {
        Id = id;
        this.acct = acct;
        this.amt1 = amt1;
        this.amt2 = amt2;   
    }
    
    public Sample(Sample sample) {
        this(sample.Id, sample.acct,sample.amt1,sample.amt2);
    }
    
    public static Sample copyOf(Sample s) {
        return new Sample(s.Id, s.acct, s.amt1,s.amt2);
    }
    
    public Sample add(Sample sample) {
        amt1 = amt1.add(sample.amt1);
        amt2 = amt2.add(sample.amt2);
        return this;
    }
    // other getters and setters
    public void setId(String id) {
        Id = id;
    }
    
    public void setAcct(String acct) {
        this.acct = acct;
    }
    
    public void setAmt1(BigDecimal amt1) {
        this.amt1 = amt1;
    }
    
    public void setAmt2(BigDecimal amt2) {
        this.amt2 = amt2;
    }
    
    public String getId() {
        return Id;
    }
    
    public String getAcct() {
        return acct;
    }
    
    public BigDecimal getAmt1() {
        return amt1;
    }
    
    public BigDecimal getAmt2() {
        return amt2;
    }

    @Override
    public String toString() {
        return String.format("[%s, %s, %s, %s]", Id, acct, amt1,
                amt2);
    }
    
}

The Data

List<Sample> collectedTxs = List.of(
        new Sample("1", "1111", new BigDecimal(".50"),
                new BigDecimal(".50")),
        new Sample("2", "1112", new BigDecimal(".50"),
                new BigDecimal(".50")),
        new Sample("2", "1112", new BigDecimal("1.50"),
                new BigDecimal("2.50")),
        new Sample("1", "1111", new BigDecimal("4.50"),
                new BigDecimal("8.50")));

The Process

  • Iterate over the list of accounts.
  • and use the merge method to combine the same accounts.
  • The acct is the key
  • s is the first encountered instance of each account.
  • and the BiFunction combines them via add using method reference
Map<String,Sample> map = new HashMap<>();
for (Sample s : collectedTxs) {
    map.merge(s.getAcct(), s, Sample::add);
}


map.forEach((k,v)-> System.out.println(k + " " + v);

prints

1112 [2, 1112, 2.00, 3.00]
1111 [1, 1111, 5.00, 9.00]

Here is the original data. Note that the first accounts encountered in the iteration were changed.

collectedTxs.forEach(System.out::println);

[1, 1111, 5.00, 9.00]
[2, 1112, 2.00, 3.00]
[2, 1112, 1.50, 2.50]
[1, 1111, 4.50, 8.50]

If you want to preserve the original instances. Then make the following change in the map construct.

map.merge(s.getAcct(),  Sample.copyOf(s), Sample::add);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文