请教一个 Java8 stream 应用问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Curiosity777
V2EX    Java

请教一个 Java8 stream 应用问题

  •  
  •   Curiosity777 2024-04-08 16:42:59 +08:00 2843 次点击
    这是一个创建于 550 天前的主题,其中的信息可能已经有所发展或是发生改变。
    请问各位大佬 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  
       2024-04-08 16:46:46 +08:00
    reduce
    wweerrgtc
        2
    wweerrgtc  
       2024-04-08 16:48:28 +08:00
    Curiosity777
        3
    Curiosity777  
    OP
       2024-04-08 16:48:32 +08:00
    @lu5je0 reduce 最后结果就是一个了
    palytoxin
        4
    palytoxin  
       2024-04-08 16:49:03 +08:00
    reduce
    ZGame
        5
    ZGame  
       2024-04-08 16:50:17 +08:00
    楼上正解,Op 可以去了解下 c# linq 的操作符,或者 js 相关的。 然后用 gpt 翻译 java 有惊喜= =
    NelsonZhao
        6
    NelsonZhao  
       2024-04-08 16:51:51 +08:00
    没必要强行用 stream ,用 for 循环自己处理呗
    Habyss
        7
    Habyss  
       2024-04-08 17:14:17 +08:00
    创建一个临时值存就可以了呀
    ```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  
       2024-04-08 17:29:15 +08:00
    巧了,上个月才做了这个需求,没必要非要用流,容易绕进去。
    cpstar
        9
    cpstar  
       2024-04-08 17:33:10 +08:00
    看了 7 楼,徒增编译器压力和代码阅读压力,…(⊙_⊙;)…
    piecezzz
        10
    piecezzz  
       2024-04-08 17:40:35 +08:00
    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  
       2024-04-08 17:41:39 +08:00
    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  
       2024-04-08 17:53:19 +08:00
    ```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  
       2024-04-08 17:56:59 +08:00
    fori 能解决 没必要强求...
    netabare
        14
    netabare  
       2024-04-08 17:58:20 +08:00 via Android   1
    reduce 里面可以是一个列表。当然 java 没有模式匹配写起来比较恶心。
    misdake
        15
    misdake  
       2024-04-08 18:29:24 +08:00
    这种东西应该是实现一个能够累加的迭代器,输出一个累加值(还可以提供当前值)的流
    Ashe007
        16
    Ashe007  
       2024-04-08 19:55:07 +08:00 via iPhone
    以 ID 为 key ,累加值为 value 的 map 来解决这个问题,无论是 for 还是 stream 都很简单,不熟练先用 for 实现,让 ai 改成 stream 实现不就好了吗?
    Leviathann
        17
    Leviathann  
       2024-04-08 20:43:21 +08:00
    不就是 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  
       2024-04-09 01:52:04 +08:00
    map+reduce 一般用在可以并行处理的场景里。
    你这里是顺序累加,不能乱序执行,不能并行,不如直接一个 for 循环搞定。
    S4msara
        19
    S4msara  
       2024-04-09 16:08:58 +08:00
    不非要用 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  
       2024-04-18 11:14:24 +08:00 via iPhone
    不要用流,遵循无状态设计必定新增中间类,撸下来性能跟内存消耗远大于常规写法
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1406 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 16:41 PVG 00:41 LAX 09:41 JFK 12:41
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86