Open4

長さが変わるストリーム処理を書きたい

Akihiro MATOBAAkihiro MATOBA

intNumberStreamからevenNumberStreamを作るとか、(長さが半分になる)
BinaryStreamからBase32Streamを作るとか、(5バイトもらって8バイト吐くので長さが1.6倍になる)
どう実装したらいいかと考えている。

https://bsky.app/profile/arton.bsky.social/post/3kkubcjtwfd27

Array#map(fn)を使えばよいのになんとなくArray#reduce(fn, [])を使って後からなんでreduce とか書いてるんだ?と不思議になることがある。

これがヒントになった。
reduceのInitialにEmptyStreamを渡せばいいのかな。試す。

Akihiro MATOBAAkihiro MATOBA

配列なら確認できた。

// javascript
[1,5,8,4,3,1,5,6].reduce(
    function (prev, curr) {
        if(prev.amount + curr > 10) {  // 次の荷物を積んだら積載超過になる場合
            prev.result.push(prev.amount);  // 今のトラックは送り出して
            prev.amount = 0;  // 空のトラックを用意する
        }
        prev.amount += curr;
        return prev;
    },
    {result:[], amount: 0}
).result
// => [6, 8, 8, 5]
Akihiro MATOBAAkihiro MATOBA

Javaの Stream.reduce は、上流と同じ型を返すか、下流の型の Combiner を書かないといけない。
原則として Parallel Stream を想定していて、長さが変わるStreamを書くのは難しそう。

二つのStreamを橋渡ししてやればいいのか? と実装してみたんだけど、止まらなくなっちゃった。

// java
IntStream.Builder b = IntStream.builder();
IntStream s = IntStream.iterate(0, n -> n+1);  // infinite stream
s.forEach(i -> b.add(i));  // 止まらない……
b.build().limit(100).forEach(System.out::println);
Akihiro MATOBAAkihiro MATOBA

こういう感じか?

// java
Iterator<Integer> s = new Iterator<Integer>() {
    int index = 0;
    public Integer next() { return index++; }
    public boolean hasNext() { return true; }
};
Iterator<Integer> r = new Iterator<Integer>() {
    public Integer next() { return s.next(); }
    public boolean hasNext() { return s.hasNext(); }
};
for(int i: (Iterable<Integer>)() -> r) {
    if(i>100) break;
    System.out.println(i);
}