如何将Fortran列主序数组转为C行主序数组,实现类NumPy索引?
在MATLAB中实现类NumPy的行主序数组索引(C语言风格)
问题描述
给定任意形状的MATLAB数组x,如何实现o = x(idx)以C语言行主序(而非MATLAB默认的Fortran列主序)进行索引,即按行主序遍历展开后的数组?
需求动机
特定场景下,行主序遍历应得到排序后的数组,例如满足isequal(x(x > 0), sort(x))。
行为匹配说明
这里的“o = x(idx)按C语言索引”指完全匹配Python NumPy的o = x[idx]行为。假设存在MATLAB数组xre实现了这种重排,那么:
xre(:)等价于 NumPy 的x.flatten()xre(i1:i2, i3:i4, i5:i6)等价于 NumPy 的x[j1:j2, j3:j4, j5:j6],其中所有索引j = i - 1(MATLAB索引从1开始,NumPy从0开始)
术语定义
- 行主序(外层优先):遍历数组时先遍历最外层维度,再依次向内层推进
- 列主序(内层优先):遍历数组时先遍历最内层维度,再依次向外层推进
注意:仅使用
permute无法实现需求,理论上也不可能——因为permute仅改变维度顺序,无法改变数组的存储结构,甚至可能因索引范围导致越界。
示例对比
MATLAB默认行为(列主序)
s = @(x, i0, i1, i2)reshape(x(i0, i1, i2), 1, []); xF = reshape(1:2*3*4, [2 3 4]); {s(xF, 1:2, 1, 1), s(xF, 1, 1:2, 1), s(xF, 1, 1, 1:2)}
输出:
{[1 2]} {[1 3]} {[1 7]}
NumPy行为(行主序)
import numpy as np xC = np.arange(1, 2*3*4+1).reshape(2, 3, 4) print(xC[0:2, 0, 0], xC[0, 0:2, 0], xC[0, 0, 0:2])
输出:
[ 1 13] [1 5] [1 2]
仅用permute的无效尝试
xp = permute(xF, [3 2 1]); {s(xp, 1:2, 1, 1), s(xp, 1, 1:2, 1), s(xp, 1, 1, 1:2)}
输出:
{[1 7]} {[1 3]} {[1 2]}
可见仅permute无法匹配NumPy的行主序索引行为。
实现方案
要在MATLAB中模拟NumPy的行主序索引,核心是将MATLAB的列主序线性索引转换为行主序线性索引,以下是完整实现:
1. 列主序转行主序线性索引函数
function idx_c = col2row_idx(idx_f, shape) % 将MATLAB原生列主序线性索引(1-based)转换为行主序线性索引(1-based) % idx_f: 输入的列主序线性索引 % shape: 数组的形状,即size(x)的输出 idx_f_0 = idx_f - 1; % 转为0-based便于计算 dims = shape; ndims = length(dims); % 计算列主序下的各维度0-based坐标 coords_f_0 = zeros(length(idx_f_0), ndims); for d = 1:ndims coords_f_0(:, d) = mod(idx_f_0, dims(d)); idx_f_0 = floor(idx_f_0 / dims(d)); end % 用行主序规则计算线性索引 idx_c_0 = 0; for d = ndims:-1:1 idx_c_0 = idx_c_0 * dims(d) + coords_f_0(:, d); end idx_c = idx_c_0 + 1; % 转回1-based索引 end
2. 类NumPy索引封装函数
function o = numpy_index(x, varargin) % 模拟NumPy的行主序索引行为,支持切片、单个索引、数组索引 % x: 输入的MATLAB数组 % varargin: 各维度的索引参数,与MATLAB原生索引格式一致(1-based) % o: 索引结果,形状匹配NumPy对应索引的输出 shape = size(x); ndims_x = ndims(x); % 将多维索引转换为MATLAB原生列主序线性索引 [~, idx_f] = sub2ind(shape, varargin{:}); % 转换为行主序线性索引 idx_c = col2row_idx(idx_f, shape); % 获取索引结果 o = x(idx_c); % 调整输出形状,匹配NumPy的切片逻辑 out_shape = []; for d = 1:length(varargin) idx = varargin{d}; out_shape = [out_shape, length(idx)]; end % 补全未指定的维度 if length(out_shape) < ndims_x out_shape = [out_shape, shape(length(out_shape)+1:end)]; end o = reshape(o, out_shape); end
3. 使用验证
xF = reshape(1:2*3*4, [2 3 4]); % 模拟NumPy的xC[0:2, 0, 0] result1 = numpy_index(xF, 1:2, 1, 1) % 输出: [1 13] % 模拟NumPy的xC[0, 0:2, 0] result2 = numpy_index(xF, 1, 1:2, 1) % 输出: [1 5] % 模拟NumPy的xC[0, 0, 0:2] result3 = numpy_index(xF, 1, 1, 1:2) % 输出: [1 2]
内容的提问来源于Stack Exchange,提问作者OverLordGoldDragon
相关产品推荐
相关产品推荐

