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纳秒

我试图理解造成这种差异的原因,发现java
array.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}