V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Curiosity777
V2EX  ›  Java

请教一个 Java8 stream 应用问题

  •  
  •   Curiosity777 · 221 天前 · 2315 次点击
    这是一个创建于 221 天前的主题,其中的信息可能已经有所发展或是发生改变。
    请问各位大佬 Java8 能实现阶段累加吗

    比如以下表
    id 当前值 累计值
    10 7.66 928.09
    9 6.56 920.43
    8 4.79 913.87
    7 6.23 909.08

    当前的累计=当前值+前一次累计

    例:
    id10 的累计值=10 的当前值+9 的累计值

    大佬们 stream 能实现吗,想半天没想出来,求指教
    20 条回复    2024-04-18 11:14:24 +08:00
    lu5je0
        1
    lu5je0  
       221 天前
    reduce
    Curiosity777
        3
    Curiosity777  
    OP
       221 天前
    @lu5je0 reduce 最后结果就是一个了
    palytoxin
        4
    palytoxin  
       221 天前
    reduce
    ZGame
        5
    ZGame  
       221 天前
    楼上正解,Op 可以去了解下 c# linq 的操作符,或者 js 相关的。 然后用 gpt 翻译 java 有惊喜= =
    NelsonZhao
        6
    NelsonZhao  
       221 天前
    没必要强行用 stream ,用 for 循环自己处理呗
    Habyss
        7
    Habyss  
       221 天前
    创建一个临时值存就可以了呀
    ```java
    // 临时累加值
    AtomicReference<Double> cumulative = new AtomicReference<>(0.0);

    // 使用流进行累计值计算
    return data.stream()
    // 排序
    .sorted(Comparator.comparingInt(DataItem::getId))
    // 看你情况是源对象处理还是返回新的对象
    .peek(item -> {
    // 累加
    cumulative.updateAndGet(v -> v + item.getCurrentValue());
    // 设置当前累计值
    item.setCumulativeValue(cumulative.get());
    })
    .collect(Collectors.toList());

    ```
    liumao
        8
    liumao  
       221 天前
    巧了,上个月才做了这个需求,没必要非要用流,容易绕进去。
    cpstar
        9
    cpstar  
       220 天前
    看了 7 楼,徒增编译器压力和代码阅读压力,…(⊙_⊙;)…
    piecezzz
        10
    piecezzz  
       220 天前
    static class Test{

    public Test(Integer id,float cur,float total){
    this.id = id;
    this.curVal = cur;
    this.totalVal = total;
    }

    public Integer id;
    public float curVal;
    public float totalVal;

    }

    public static void main(String[] args) {
    Test one = new Test(10,7.66f,928.09f);
    Test two = new Test(9,6.56f,920.43f);
    Test three = new Test(8,4.79f,913.87f);
    Test four = new Test(7,6.23f,909.08f);

    Stream.of(one,two,three,four).sorted(Comparator.comparing(t -> t.id))
    .reduce((prev, cur) -> {
    cur.totalVal += prev.curVal;
    return cur;
    });
    System.out.println(one.totalVal);
    }
    ocean1477
        11
    ocean1477  
       220 天前
    mysql 的情况下 sql 也可以啊
    select id, cur_val + lag(acc_val, 1, 0) over (order by id) as sum_val from test order by id desc;
    java8 的话也行
    ```java
    MyObj obj1 = new MyObj(10, 7.66, 928.09, 0.0);
    MyObj obj2 = new MyObj(9, 6.56, 920.43, 0.0);
    MyObj obj3 = new MyObj(8, 4.79, 913.87, 0.0);
    MyObj obj4 = new MyObj(7, 6.23, 909.08, 0.0);
    List<MyObj> list = Lists.newArrayList(obj4, obj3, obj2, obj1);
    MyObj res = list.stream().reduce(new MyObj(0, 0.0, 0.0, 0.0), (prev, curr) -> {
    curr.setSumVal(prev.getAccVal() + curr.getCurVal());
    return curr;
    }, (a, b) -> a);
    list.forEach(System.out::println);
    ```
    Karte
        12
    Karte  
       220 天前
    ```java
    public class StreamTest {


    private List<C> initialSequence() {
    var res = new ArrayList<C>();

    var rand = new Random(0);
    for (int i = 0; i < 10; i++) {
    C c = new C();
    c.setId(i);
    c.setCurrent(rand.nextInt(1000));
    res.add(c);
    }

    return res;
    }

    @Test
    public void stream() {
    List<C> sequence = initialSequence();
    System.out.println("before");
    output(sequence);


    C finalResult = sequence.stream().reduce(new C(), (pre, now) -> {
    Integer accumulative = Optional.ofNullable(pre.getAccumulative()).orElse(0);
    now.setAccumulative(accumulative + now.getCurrent());
    return now;
    });


    System.out.println("after");
    output(sequence);
    }

    private void output(List<C> sequence) {
    for (C c : sequence) {
    System.out.println(String.format("id: %s, acc: %d", c.getId(), c.getAccumulative()));
    }
    }

    static class C {

    private Integer id;

    private Integer accumulative;

    private Integer current;

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    public Integer getAccumulative() {
    return accumulative;
    }

    public void setAccumulative(Integer accumulative) {
    this.accumulative = accumulative;
    }

    public Integer getCurrent() {
    return current;
    }

    public void setCurrent(Integer current) {
    this.current = current;
    }
    }

    }
    ```

    无视 reduce 的结果即可.
    nitmali
        13
    nitmali  
       220 天前
    fori 能解决 没必要强求...
    netabare
        14
    netabare  
       220 天前 via Android   ❤️ 1
    reduce 里面可以是一个列表。当然 java 没有模式匹配写起来比较恶心。
    misdake
        15
    misdake  
       220 天前
    这种东西应该是实现一个能够累加的迭代器,输出一个累加值(还可以提供当前值)的流
    Ashe007
        16
    Ashe007  
       220 天前 via iPhone
    以 ID 为 key ,累加值为 value 的 map 来解决这个问题,无论是 for 还是 stream 都很简单,不熟练先用 for 实现,让 ai 改成 stream 实现不就好了吗?
    Leviathann
        17
    Leviathann  
       220 天前
    不就是 scan 吗

    或者 reduce 成一个 list

    `10 7.66 928.09
    9 6.56 920.43
    8 4.79 913.87
    7 6.23 909.08`
    .split('\n')
    .reverse()
    .map(line => line.split(' '))
    .map(([id, value, accu]) => ({
    id: Number(id),
    value: Number(value),
    accu: Number(accu)
    }))
    .reduce((result, cur) => {
    const last = result[result.length - 1]
    if (last) {
    result.push({...cur, accu: last.accu + cur.value})
    } else {
    result.push(cur)
    }
    return result
    }, [])
    msg7086
        18
    msg7086  
       220 天前
    map+reduce 一般用在可以并行处理的场景里。
    你这里是顺序累加,不能乱序执行,不能并行,不如直接一个 for 循环搞定。
    S4msara
        19
    S4msara  
       220 天前
    不非要用 Stream 实现的话可以参考:

    ```java
    public List<Record> greeting(List<Record> list) {
    ListIterator<Record> iterator = list.listIterator();
    while (iterator.hasNext()) {
    Double preTotal = null;
    if (iterator.previousIndex() != -1) {
    Record previous = iterator.previous();
    preTotal = previous.getTotal();
    iterator.next();
    }
    Record next = iterator.next();
    if (preTotal != null) {
    next.setTotal(preTotal + next.getCurr());
    }
    iterator.set(next);
    }
    return list;
    }
    ```
    siweipancc
        20
    siweipancc  
       211 天前 via iPhone
    不要用流,遵循无状态设计必定新增中间类,撸下来性能跟内存消耗远大于常规写法
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5208 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 09:31 · PVG 17:31 · LAX 01:31 · JFK 04:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.