我正在尝试以固定尺寸切割一个数组并将结果放入另一个数组中 本质上会创建一个不均匀的矩阵
我找到了这个解决方案:
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]]
答案 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
有点慢,然后创建固定大小的数组然后复制数据
此外,如果您会在数组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
所做的事情,我们共享它,但是只使用offset
和length
来标识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}