在Java 8中有办法实现Ruby的each_slice吗?



如果我有一个数组

[1, 2, 3, 4, 5, 6, 7, 8, 9]

并且希望将其分成3个组,我可以使用.each_slice(3),如下所示

[1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(3).to_a => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

是否有一种方法可以在Java 8中做类似的事情?

Ruby enumerable

我想出了这个解决方案:

public static int[][] slice(int[] arr, int n) {
    return IntStream.range(0, (int) Math.ceil((double) arr.length / n))
            .mapToObj(i -> Arrays.copyOfRange(arr, i * n, Math.min((i + 1) * n, arr.length)))
            .toArray(int[][]::new);
}

有,但是据我所知没有一种优雅的单方法方法。您需要编写自己的数组切片方法,就像这样(讨厌的,不优雅的方式):

public static int[][] slice(int[] source, int n) {
    List<int[]> results = new ArrayList<int[]>();
    int len = (source.length % n == 0 ? source.length/n : source.length / n + 1);
    for(int i = 0; i < len; i++) {
        results.add(Arrays.copyOfRange(source, i * n, (i+1 == len ? source.length : (i+1)*len)));
    }
    return results.toArray(new int[][]{});
}

我喜欢上面提出的解决方案,但不知何故它不能在我的IntelliJ中编译。我使用了他的解决方案,只是稍微修改了一下,写下了下面的方法sliceUsingJavaStreams。我的代码的另一件事是,即使数组不能完全切片,它也能工作,例如,具有元素{1,2,3,4,5,6,7,8,9,10}的数组将在以下代码中被切片为[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]:

不使用流:

public static int[][] slice(int[] array, int sliceSize) {
        int slicesCount = (int) Math.ceil(array.length/(double)sliceSize);
        int[][] results = new int[slicesCount][];
        int[] sliceArray;
        int index = 0;
        for(int i=array.length; i>0; i=i-sliceSize) {
            int start = array.length-i;
            int last = ((start+sliceSize) < array.length)? (start+sliceSize) : (array.length);
            sliceArray = Arrays.copyOfRange(array,start,last);
            results[index++] = sliceArray;
        }
        return results;
    }
使用流

:

public static int[][] sliceUsingJavaStreams(int[] arr, int n) {
        return IntStream.range(0, (int) Math.ceil(arr.length / (double) n))
                .mapToObj(new IntFunction<int[]>() {
                    @Override
                    public int[] apply(int i) {
                        return Arrays.copyOfRange(arr, i * n, Math.min((i + 1) * n, arr.length));
                    }
                }).toArray(int[][]::new);
    }

现在我可以测试它们为:

public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        final int n = 3;
        int[][] slicedArrayOne = slice(array,3);
        int[][] slicedArrayTwo = sliceUsingJavaStreams(array,3);
        System.out.println(Arrays.deepToString(slicedArrayOne));
        System.out.println(Arrays.deepToString(slicedArrayTwo));
    }

输出为:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]] [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

如果您不介意依赖优秀的Guava库,您可以使用Lists。

应该不难添加。

迭代输入。每n个元素加一个新的桶。在那里添加条目:

public static <T> List<List<T>> eachSlice(List<T> input, int size) {
    List<List<T>> r = new ArrayList<List<T>>();
    for( int i = 0 ; i < input.size(); i++ ) { // iterate input
        if ( i % size == 0 ) {                 // every n elements
            r.add(new ArrayList<T>());         // add bucket
        }
        r.get(r.size()-1).add(input.get(i));   // add current element to bucket
    }
    return r;
}

你可以import static这个函数并使用它,例如

import static java.lang.System.out;
import static something.Util.eachSlice;
class Main {
    public static void main( String ... args ) {
        List<Integer> input = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        List<List<Integer>> output  = eachSlice( input , 3);
        out.println( output );
    }
}
输出:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

最新更新