Java将数组切割成不均匀矩阵的最快方法
我试图在一个固定的维度上切割一个数组,然后将结果放入另一个数组中 本质上是创建一个不均匀的矩阵 我找到了这个解决方案:Java将数组切割成不均匀矩阵的最快方法,java,arrays,matrix,Java,Arrays,Matrix,我试图在一个固定的维度上切割一个数组,然后将结果放入另一个数组中 本质上是创建一个不均匀的矩阵 我找到了这个解决方案: public static void main(String[] args) { System.out.println(Arrays.deepToString(matrixize(2, 1, 2, 3, 4, 5, 6, 7, 8, 9))); } public static Object[][] matrixize(int cutat, Object...
public static void main(String[] args) {
System.out.println(Arrays.deepToString(matrixize(2, 1, 2, 3, 4, 5, 6, 7, 8, 9)));
}
public static Object[][] matrixize(int cutat, Object... data) {
int rows = (int) Math.ceil(data.length / (double) cutat);
Object[][] matrix = new Object[rows][];
for (int i = 0; i < rows; i++) {
matrix[i] = Arrays.copyOfRange(data, cutat * i, Math.min(data.length, cutat * (i + 1)));
}
return matrix;
}
- 有没有更快的方法李>
列表
,那么您可以避免所有的数组复制,如果这些数组可以变大,这将是一个显著的好处
请注意,使用此解决方案,写入结果矩阵将写入原始数据,这可能是好事,也可能是坏事
private static class ArraySlice<T> extends AbstractList<T> {
private final T[] data;
private final int start;
private final int length;
public ArraySlice(T[] data, int start, int length) {
this.data = data;
this.start = start;
this.length = length;
}
@Override
public T get(int index) {
if(index > length) throw new IndexOutOfBoundsException("Out of bounds");
return data[start + index];
}
@Override
public int size() {
return length;
}
}
public static <T> List<List<T>> matrixize(int cutat, T... data) {
List<List<T>> matrix = new ArrayList<>();
for(int i = 0; i < data.length; i += cutat) {
matrix.add(new ArraySlice(data, i, Math.min(cutat, data.length - i)));
}
return matrix;
}
public void test() {
List<List<Integer>> matrix = matrixize(2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(matrix);
}
私有静态类ArraySlice扩展了AbstractList{
私有最终T[]数据;
私人最终启动;
私有最终整数长度;
公共阵列片(T[]数据,整数开始,整数长度){
这个数据=数据;
this.start=start;
这个长度=长度;
}
@凌驾
公共T获取(整数索引){
如果(索引>长度)抛出新的IndexOutOfBoundsException(“超出范围”);
返回数据[开始+索引];
}
@凌驾
公共整数大小(){
返回长度;
}
}
公共静态列表矩阵(int cutat,T…data){
列表矩阵=新的ArrayList();
对于(int i=0;i
这张照片是:
[1,2]、[3,4]、[5,6]、[7,8]、[9]]
如果您真的需要使用阵列,那么您的速度就无法显著提高 但是,如果您可以使用
列表
,那么您可以避免所有的数组复制,如果这些数组可以变大,这将是一个显著的好处
请注意,使用此解决方案,写入结果矩阵将写入原始数据,这可能是好事,也可能是坏事
private static class ArraySlice<T> extends AbstractList<T> {
private final T[] data;
private final int start;
private final int length;
public ArraySlice(T[] data, int start, int length) {
this.data = data;
this.start = start;
this.length = length;
}
@Override
public T get(int index) {
if(index > length) throw new IndexOutOfBoundsException("Out of bounds");
return data[start + index];
}
@Override
public int size() {
return length;
}
}
public static <T> List<List<T>> matrixize(int cutat, T... data) {
List<List<T>> matrix = new ArrayList<>();
for(int i = 0; i < data.length; i += cutat) {
matrix.add(new ArraySlice(data, i, Math.min(cutat, data.length - i)));
}
return matrix;
}
public void test() {
List<List<Integer>> matrix = matrixize(2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(matrix);
}
私有静态类ArraySlice扩展了AbstractList{
私有最终T[]数据;
私人最终启动;
私有最终整数长度;
公共阵列片(T[]数据,整数开始,整数长度){
这个数据=数据;
this.start=start;
这个长度=长度;
}
@凌驾
公共T获取(整数索引){
如果(索引>长度)抛出新的IndexOutOfBoundsException(“超出范围”);
返回数据[开始+索引];
}
@凌驾
公共整数大小(){
返回长度;
}
}
公共静态列表矩阵(int cutat,T…data){
列表矩阵=新的ArrayList();
对于(int i=0;i
这张照片是:
[1,2]、[3,4]、[5,6]、[7,8]、[9]]
虽然您的代码非常好,而且看起来速度相当快,但下面的代码运行速度要快一点: 您的代码平均执行时间(10次尝试):19158纳秒 低于代码平均执行时间(10次尝试):14891纳秒 我试图理解造成这种差异的原因,发现java
array.copy
在创建固定大小的数组然后复制数据时有点慢
此外,如果您在Arrays
copyOfRange
方法中看到,执行了两条语句,而要进行复制,我们只需要将现有变量的引用从一个数组复制到另一个数组。虽然您的代码非常好,而且看起来相当快,但下面的代码运行速度要快一点:
您的代码平均执行时间(10次尝试):19158纳秒
低于代码平均执行时间(10次尝试):14891纳秒
我试图理解造成这种差异的原因,发现javaarray.copy
在创建固定大小的数组然后复制数据时有点慢
此外,如果您将在Arrays
copyOfRange
方法中看到,执行了两条语句,而要进行复制,我们只需要将现有变量的引用从一个数组复制到另一个数组。如果是原始速度,您可以让它先创建固定大小的数组(接受“离群值”)到
参数),并在需要时单独截断最后一个元素,可能使用一些模校验。同样,可以用整数算法实现
行的魔法:introws=(data.length+cutat-1)/cutat代码>
比如:
int rows=(data.length+cutat-1)/cutat;
Object[][] matrix=new Object[rows][];
for(int i=0;i<data.length;i+=cutat)
matrix[i]=Arrays.copyOfRange(data,i,i+cutat);
int mod=data.length % cutat;
if(mod>0)
matrix[rows-1]=Arrays.copyOfRange(matrix[rows-1],0,mod);
int rows=(data.length+cutat-1)/cutat;
对象[][]矩阵=新对象[行][];
对于(int i=0;i0)
矩阵[rows-1]=数组.copyOfRange(矩阵[rows-1],0,mod);
但我并不是说它真的会比原来的“更快”,它更像是一种不同的风格
如果您有大量数据,保持数据不变可能会更快,并使用简单的[x+y*width]
-样式索引以“2D方式”从1D存储访问元素。如果是原始速度,您可以让它先创建固定大小的数组(接受“outlier”到
参数),从而稍微加快速度,并在需要时单独截断最后一个元素,可能使用一些模检查。
同样,可以用整数算法实现行的魔法:introws=(data.length+cutat-1)/cutat代码>
比如:
int rows=(data.length+cutat-1)/cutat;
Object[][] matrix=new Object[rows][];
for(int i=0;i<data.length;i+=cutat)
matrix[i]=Arrays.copyOfRange(data,i,i+cutat);
int mod=data.length % cutat;
if(mod>0)
matrix[rows-1]=Arrays.copyOfRange(matrix[rows-1],0,mod);
int rows=(data.length+cutat-1)/cutat;
对象[][]矩阵=新对象[行][];
对于(int i=0;i0)
矩阵[rows-1]=数组.copyOfRange(矩阵[rows-1],0,mod);
但我并不是说它真的会比原始版本“更快”
int rows=(data.length+cutat-1)/cutat;
Object[][] matrix=new Object[rows][];
for(int i=0;i<data.length;i+=cutat)
matrix[i]=Arrays.copyOfRange(data,i,i+cutat);
int mod=data.length % cutat;
if(mod>0)
matrix[rows-1]=Arrays.copyOfRange(matrix[rows-1],0,mod);
public class CutArrayToMatrix {
public static void main(String... args) {
test(CutArrayToMatrix::matrixizeByCopy);
test(CutArrayToMatrix::matrixize);
}
private static void test(BiConsumer<Integer, Object[]> biConsumer) {
int testTimes = 50;
List<Integer> list = new ArrayList<>();
Long start;
List<Long> timer = new ArrayList<>();
for (int i = 0; i < testTimes; ++i) {
int N = new Random().nextInt(500) + 100_000;
for (int j = 0; j < N; ++j) {
list.add(new Random().nextInt());
}
Object[][] oo1 = matrixize(30, list.toArray());
Object[][] oo2 = matrixizeByCopy(30, list.toArray());
assert oo1.length == oo2.length : "length not equal";
assert oo1[oo1.length - 1].length == oo2[oo2.length - 1].length : "last not equal";
start = System.nanoTime();
biConsumer.accept(30, list.toArray());
timer.add(System.nanoTime() - start);
}
System.out.println(timer.stream().collect(Collectors.summarizingLong(Long::longValue)));
}
public static Object[][] matrixizeByCopy(Integer cutat, Object... data) {
int rows = (int) Math.ceil(data.length / (double) cutat);
Object[][] matrix = new Object[rows][cutat];
int i = 0;
int rowIndex = 0;
while (i < data.length) {
for (int j = 0; j < cutat; ++j) {
matrix[rowIndex][j] = data[i++];
if (i == data.length) return matrix;
}
rowIndex++;
}
return matrix;
}
public static Object[][] matrixize(int cutat, Object... data) {
int rows = (int) Math.ceil(data.length / (double) cutat);
Object[][] matrix = new Object[rows][];
for (int i = 0; i < rows; i++) {
matrix[i] = Arrays.copyOfRange(data, cutat * i, Math.min(data.length, cutat * (i + 1)));
}
return matrix;
}
}
// Aman Chhabra's solution (actually I followed his thought but fixed the bugs in his code)
LongSummaryStatistics{count=50, sum=666080821, min=5757846, average=13321616.420000, max=33013518}
// your solution;
LongSummaryStatistics{count=50, sum=329080566, min=1709920, average=6581611.320000, max=57146002}