範囲の幅から計算した範囲の数ではなく最大値で制限した範囲の処理をする課題が目的、
範囲の数を指定できる場合と比べていく。
Java の場合、
範囲幅=100 で、5個の範囲の処理、この 5個と指定できる場合は次のように簡単に書ける。
すなわち、IntStream.rangeClosed を使える場合、
IntStream.rangeClosed(1, 5).boxed() .map(i->new int[]{ (i - 1) * 100 + 1, i * 100 }) .forEach(n->{ System.out.println(n[0] + " - "+ n[1]); // TODO 範囲 n[0] から n[1] の処理 });
1 - 100 101 - 200 201 - 300 301 - 400 401 - 500
このように範囲の生成を予め指定できないケースではどうするか?
無限イテレータに対して、最大値で限定する方法
最大値=500 を指定したい時、、
Java9 以降では Stream に takeWhile がある。
IntStream.iterate(1, i->i+1) .mapToObj(i->new int[]{ (i - 1) * 100 + 1, i * 100 }) .takeWhile(n->n[1] <= 500) .forEach(n->{ System.out.println(n[0] + " - "+ n[1]); // TODO 範囲 n[0] から n[1] の処理 });
Java8 ではこの takeWhile が使えないので、
https://oboe2uran.hatenablog.com/entry/2020/04/18/192429
で作成した whilestream メソッドを用意して
以下のようにする。
whilestream(IntStream.iterate(1, i->i+1) .mapToObj(i->new int[]{ (i - 1) * 100 + 1, i * 100 }) , n->n[1] <= 500 ).forEach(n->{ System.out.println(n[0] + " - "+ n[1]); // TODO 範囲 n[0] から n[1] の処理 });
Python の場合、
範囲の数を指定できる range を使う場合は簡単で、リスト内包表記で
範囲のタプルのリスト生成で処理できる。
for t in ((i*100+1, (i+1)*100) for i in range(5)): print(t)
(1, 100) (101, 200) (201, 300) (301, 400) (401, 500)
最大値で限定する方法
以下のメソッド、0から始まる数の無限ジェネレータ count() から
範囲を生成するジェネレータ用意して、最大値でループを抜ける
def count(): c = 0 while True: yield c c += 1 def makerange(len:int): counter = count() while True: i = counter.__next__() yield (i * len + 1, (i + 1) * len) for t in makerange(100): print(t) # TODO tuple [0] [1] を使用する if t[1] >= 500: break
この count() は、itertools.count() で置き換えられるので、
import itertools for i in itertools.count(): t = (i * 100 + 1, (i + 1) * 100) print(t) # TODO tuple [0] [1] を使用する if t[1] >= 500: break
と簡潔にすることが可能
範囲の幅と最大値を指定できるようにif文を含むメソッドにすれば、
もっと簡潔になる。
import itertools def makerange(len:int, max:int): for i in itertools.count(): t = (i * len + 1, (i + 1) * len) yield t if t[1] >= max: break for t in makerange(100, 500): print(t) # TODO tuple [0] [1] を使用する