Javaでrange
Javaでtimesのつづき。
前回はJavaでRubyのtimesっぽいものを作って++を隠蔽したけど、まぁお世辞にも使いやすいとは言いがたい。一番の問題は、回数数えるだけなのに記述量が多いことだと思う。
ということで、今回は記述量もそれなりになるように、PythonのrangeをJavaで真似してみる。
負の数を指定したときとかの動作は迷ったけど、まぁ結構自然な動作かな。
public final class RangeUtils { private static final int[] EMPTY = new int[0]; private RangeUtils() {} public static int[] rangeBySize(int size, int step) { int[] result = new int[size]; for (int i = 0; i < size; i++) result[i] = i * step; return result; } public static int[] rangeBySize(int size) { return rangeBySize(size, 1); } public static int[] rangeUntil(int end, int step) { if (end == 0) return new int[] { 0 }; if (step == 0) throw new IllegalArgumentException(); int diff = (step < 0 ? -step : step); int size = (end < 0 ? -end : end) / diff + 1; int[] result = new int[size]; for (int i = 0; i < size; i++) result[i] = i * (end < 0 ? -diff : diff); return result; } public static int[] rangeUntil(int end) { return rangeUntil(end, 1); } public static int[] rangeBetween(int start, int end) { if (start == end) return EMPTY; int size = (start < end ? end - start : start - end) + 1; int[] result = new int[size]; for (int i = 0; i < size; i++) result[i] = i + start; return result; } public static int[] allSameValue(int size, int value) { int[] result = new int[size]; for (int i = 0; i < size; i++) result[i] = value; return result; } }
で、使うときはstaticインポートして、
// 0 1 2 3 4 5 6 7 8 9 for (int i : rangeBySize(10)) System.out.print(i + " "); System.out.println(); // 0 1 2 3 4 5 6 7 8 9 10 for (int i : rangeUntil(10)) System.out.print(i + " "); System.out.println(); // 1 2 3 4 5 6 7 8 9 10 for (int i : rangeBetween(1, 10)) System.out.print(i + " "); System.out.println();
な感じ。
rangeBySizeは第一引数で指定したサイズのint型配列を生成する。
第二引数がなければ1ずつ、あれば第二引数に指定した数ずつ0から増やしていく。第一引数に負の数は指定できないが、第二引数には指定でき、その際の動作は0から減っていく。
rangeUntilは、第一引数に指定した数までのint型配列を生成する。
第二引数がなければ1ずつ、あれば第二引数に指定した数ずつ0から増やしていく。rangeBySizeと違い、第一引数に負の数を指定することもできる。第一引数に負の数を指定した場合、0から減っていく配列が生成される。
第二引数には0以外の数が指定できる。ただし、負の数は正の数が渡されたものとして動作する*1。
また、rangeBySizeは第一引数に指定したサイズの配列が生成されるが、rangeUntilは第一引数を含む0からの配列が生成されるため、第一引数はサイズを表さない。
rangeBetweenは初期数値が設定できるrangeUntilのような動作である。基本的には第一引数以上第二引数以下の配列を生成する。
ただし、第二引数よりも第一引数の方が大きい場合は、第一引数以下第二引数以上の配列を生成する。
for (int i : rangeBetween(1, size)) { ... }
のように記述できる。timesよりもはるかに実用的かも。