Java将数组切成不均匀矩阵的最快方法

时间:2018-07-26 10:31:39

标签: 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... 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;
}

预期结果是:

[[1, 2], [3, 4], [5, 6], [7, 8], [9]]
  • 有更快的方法吗?

4 个答案:

答案 0 :(得分:2)

如果真的需要使用数组,您将无法真正获得更快的速度。

但是,如果您可以使用creating index... index created! creating index... index created! Running per image evaluation... Evaluate annotation type *bbox* DONE (t=0.07s). Accumulating evaluation results... DONE (t=0.02s). Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.000 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.000 Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.000 Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000 Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.000 Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.000 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.000 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.000 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.000 Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000 Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.000 Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.000 来代替,那么您可以避免所有该数组的复制,如果这些数组可以变大,这将是一个很大的收获。

请注意,使用此解决方案,写入结果矩阵将写入原始数据,这可能是好事也可能是坏事。

List<List<>>

此打印:

  

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

答案 1 :(得分:1)

尽管您的代码非常好,而且看起来很快,但是下面的代码却可以更快地

  

您的代码平均执行时间(10次尝试): 19158纳秒

     

以下代码平均执行时间(尝试10次): 14891纳秒

public Object[][] matrixize(int cutat, Object... data) {
    int rows = (int) Math.ceil(data.length / (double) cutat);
    Object[][] matrix = new Object[rows][cutat];
    int matrIndex = 0, i = 0;
    for (; i < data.length-1; i++) {
        for (int j=0; j < cutat; j++) {
            matrix[matrIndex][j] = data[i];
            i++;
        }
        matrIndex++;
        --i;
    }
    if(i<data.length) matrix[matrIndex] = new Object[]{data[i]};
    return matrix;
}

输出:

jshell> System.out.println(Arrays.deepToString(matrixize(2,     1, 2, 3, 4, 5, 6, 7, 8, 9)));
[[1, 2], [3, 4], [5, 6], [7, 8], [9]]

我试图了解造成这种差异的原因是什么,发现Java Arrays.copy有点慢,然后创建固定大小的数组然后复制数据

Need of a faster array copy

此外,如果您会在数组copyOfRange方法中看到,则正在执行几条语句,而要复制,我们只需要将现有变量的引用从一个数组复制到另一个数组即可。

答案 2 :(得分:1)

如果是关于原始速度的,则可以通过使其先创建固定大小的数组(copyOfRange()接受“异常值” to参数)来稍微提高速度,并在出现以下情况时分别截断最后一个元素需要,也许使用一些模检查。
同样,可以使用整数算术rows完成int rows=(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);

但是我没有说它真的会比原始版本“更快”,它更像是一种不同的样式。

如果您有大量数据,则保持其不变的速度可能更快,并使用简单的[x+y*width]样式索引来从1D存储中以“ 2D方式”访问元素。

答案 3 :(得分:1)

这不是不是答案,我正在尝试澄清一些问题,这可能有助于您的优化。

首先,Aman Chhabra的观点和分析尚可,但不准确,并且他的解决方案首先未正确测试,并且越过了数组边界,无法在内部循环中测试数组,最后一行也不正确。

第二,OldCurmudgeon提供了我们经常遇到的非常有见地的视图,以节省时间并提高 space time 的性能。一个典型的例子是我们对substring所做的事情,我们共享它,但是只使用offsetlength来标识sub以避免复制和<浪费了strong>多余的空间。

我们共享背后的数据并将详细信息封装在一个对象/实例中,但提供使用的必要/必要接口。

OldCurmudgeon已经提供了这种设计的演示。您应该遵循这个想法并标记他的答案。

无论如何,这是一个演示Aman Chhabra解决方案思想的演示,该演示强有力地证明了您的解决方案虽然Aman Chhabra提到了许多可能的开销,但解决方案速度更快,但我只是相信随机测试用例只能证明事实。

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}