如果我有一个数组
[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]]