
本文介绍在 ojAlgo 库中对 Primitive64Matrix(新版为 MatrixR064)或可变矩阵 Primitive64Store 的每行进行高效排序的正确实践,避免低效拷贝,推荐使用 RowView + ArrayR064 缓冲区的组合方式。
本文介绍在 ojalgo 库中对 `primitive64matrix`(新版为 `matrixr064`)或可变矩阵 `primitive64store` 的每行进行高效排序的正确实践,避免低效拷贝,推荐使用 `rowview` + `arrayr064` 缓冲区的组合方式。
ojAlgo 中的 Primitive64Matrix(在 v49+ 已重命名为 MatrixR064)是不可变(immutable)矩阵类型,这意味着任何“修改”操作(如替换某一行)都必须通过 .copy() 创建新实例,导致额外内存分配与性能开销——正如原始代码中 receiver = matrix.copy() 所体现的那样。因此,若需频繁行级更新,应优先选用可变存储类型 Primitive64Store;若必须使用 MatrixR064,则需接受一次性的完整重建。
✅ 推荐方案一:使用 Primitive64Store(推荐,支持就地修改)
Primitive64Store 是可变的底层存储实现,允许直接调用 fillRow() 修改指定行,无需复制整个矩阵:
double[][] tab = { { 1, 3, 4, 2 }, { 0, 4, 3, 1 } };
Primitive64Store matrix = Primitive64Store.FACTORY.rows(tab); // 可变存储
// 复用缓冲区,避免重复创建数组
ArrayR064 temp = ArrayR064.make(matrix.getColDim());
for (RowView<double> rowView : matrix.rows()) {
rowView.supplyTo(temp.data); // 将当前行数据提取到 temp.data
Arrays.sort(temp.data); // 原地排序
matrix.fillRow(rowView.row(), temp); // 将排序后数据写回该行
}</double>
✅ 优势:零矩阵拷贝、内存友好、语义清晰;
⚠️ 注意:确保 temp 容量与列数一致(getColDim()),且 fillRow(int, ArrayR064) 会按列顺序写入,与 supplyTo 提取顺序一致。
✅ 推荐方案二:使用 MatrixR064(仅当必须用不可变类型时)
若业务逻辑强依赖不可变性(如函数式链式调用、线程安全快照),则需一次性构建新矩阵:
double[][] tab = { { 1, 3, 4, 2 }, { 0, 4, 3, 1 } };
MatrixR064 matrix = MatrixR064.FACTORY.rows(tab);
DenseReceiver receiver = matrix.copy(); // 仅一次拷贝
ArrayR064 temp = ArrayR064.make(matrix.getColDim());
for (RowView<double> rowView : matrix.rows()) {
rowView.supplyTo(temp.data);
Arrays.sort(temp.data);
receiver.fillRow(rowView.row(), temp);
}
matrix = receiver.get(); // 获取排序后的新不可变矩阵</double>
? 关键优化点:
- 使用 RowView 替代 matrix.row(i).toRawCopy1D(),避免每次生成新数组;
- 复用 ArrayR064 实例,而非在循环内新建 double[];
- fillRow(int, ArrayR064) 比 fillRow(int, MatrixR064) 更轻量,因后者需额外封装。
❌ 不推荐做法(原始代码问题分析)
final double[] rowSorted = matrix.row(iRow).toRawCopy1D(); // → 每次创建新数组 receiver.fillRow(iRow, Primitive64Matrix.FACTORY.rows(rowSorted)); // → 再次封装为矩阵,低效
该写法存在三重冗余:
- toRawCopy1D() 强制复制整行;
- FACTORY.rows(...) 将一维数组包装为临时单行矩阵;
- fillRow 内部仍需解包该矩阵 → 显著拖慢性能。
总结
- 首选 Primitive64Store:适用于大多数需行级编辑的场景,支持真正就地排序;
- 慎用 MatrixR064:仅在需要不可变语义时采用,并通过 DenseReceiver 批量构建;
- 始终复用 ArrayR064 缓冲区,避免 double[] 频繁分配;
- 避免 row().toRawCopy1D() + FACTORY.rows() 组合,这是性能瓶颈主因。
掌握这些模式,即可在 ojAlgo 中以接近原生数组的效率完成矩阵行排序任务。











