配列の分割

Java の配列を、一定の長さでちぎって分割したい …って、そういう応用って結構ありそうな気がするんだけど、ない?

ということでざっと書いてみた。オブジェクトの配列ならジェネリクスで全部まるっと書けるんだけれど、組み込み型の int や long、 boolean については同じコードをコピペしないとダメってあたり、ジェネリクスはイケてないなあ。

import static org.junit.Assert.*;

import java.lang.reflect.Array;
import org.junit.Test;

public class ArraySplitTest {

    @Test
    public void test1() {
        final Long[] original = from(new long[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 });
        final Long[][] expected = { from(new long[] { 1, 2, 3, 4 }),
                from(new long[] { 5, 6, 7, 8 }), from(new long[] { 9, 0 }) };
        assertArrayEquals(expected, splitArray(original, 4));
    }

    @Test
    public void test2() {
        final Long[] original = from(new long[] { 1, 2, 3 });
        final Long[][] expected = { from(new long[] { 1, 2, 3 }) };
        assertArrayEquals(expected, splitArray(original, 3));
    }

    @Test
    public void test3() {
        final Long[] original = from(new long[] { 1 });
        final Long[][] expected = { from(new long[] { 1 }) };
        assertArrayEquals(expected, splitArray(original, 10));
    }

    @Test
    public void test4() {
        final Long[] original = from(new long[] {});
        final Long[][] expected = new Long[0][];
        assertArrayEquals(expected, splitArray(original, 10));
    }

    static Long[] from(long[] vs) {
        Long[] array = new Long[vs.length];
        for (int i = 0, N = vs.length; i < N; ++i) {
            array[i] = Long.valueOf(vs[i]);
        }
        return array;
    }

    /**
     * 渡された配列を、長さ length の配列に分割して返す。
     * 
     * 末尾の配列は、もとの配列のうち length で割り切れなかった残りの要素を格納する。
     * 
     * @param array
     *        分割する配列。
     * @param length
     *        分割した各配列の長さ。 1 以上。 1 未満の値を指定したときの動作は不定。
     * @return 分割した配列。
     */
    static long[][] splitArray(long[] array, int length) {
        final int originalLength = array.length;
        final int div = originalLength / length;
        final int mod = originalLength % length;
        final long[][] subarray = new long[div + (mod > 0 ? 1 : 0)][];
        for (int i = 0; i < div; ++i) {
            subarray[i] = new long[length];
            System.arraycopy(array, i * length, subarray[i], 0, length);
        }
        if (mod > 0) {
            subarray[div] = new long[mod];
            System.arraycopy(array, div * length, subarray[div], 0, mod);
        }
        return subarray;
    }

    static <T> T[][] splitArray(T[] array, int length) {
        final int div = array.length / length;
        final int mod = array.length % length;
        final T[][] subarray = newArrayOfArrayT(array, div + (mod > 0 ? 1 : 0));
        for (int i = 0; i < div; ++i) {
            subarray[i] = newArrayOfT(array, length);
            System.arraycopy(array, i * length, subarray[i], 0, length);
        }
        if (mod > 0) {
            subarray[div] = newArrayOfT(array, mod);
            System.arraycopy(array, div * length, subarray[div], 0, mod);
        }
        return subarray;
    }

    static <T> T[][] newArrayOfArrayT(final T[] array, int length) {
        return (T[][]) Array.newInstance(array.getClass(), length);
    }

    static <T> T[] newArrayOfT(T[] array, int length) {
        return (T[]) Array.newInstance(array.getClass().getComponentType(), length);
    }

}