按字段名和一些非顺序索引选择一个结构元素
Pick a struct element by field name and some non-sequential index
我的意思是用一个结构来保存一个“table”:
% Sample data
% idx idxstr var1 var2 var3
% 1 i01 3.5 21.0 5
% 12 i12 6.5 1.0 3
第一行包含字段名称。
假设我创建了一个结构
ds2 = struct( ...
'idx', { 1, 12 }, ...
'idxstr', { 'i01', 'i12' }, ...
'var1', { 3.5, 6.5 }, ...
'var2', { 21, 1 }, ...
'var3', { 5, 3 } ...
);
如何检索字段 var2
的值,对应于 idxstr
等于 'i01'
的行?
备注:
- 我无法确保
idxstr
个元素的长度始终为 3。
- 理想情况下,我会有一种方法也适用于包含字符串或任何其他类型变量的列
var2
。
PS:我认为 可以提供帮助。
假设 idxstr
可以超过 3 个字符(它总是 3 个字符有一个更短的版本),这就是我想出的(在 MATLAB 上测试过):
logical_index=~cellfun(@isempty,strfind({ds2(:).idxstr},'i01'))
您可以通过以下方式访问变量:
ds2(~cellfun(@isempty,strfind({ds2(:).idxstr},'i01'))).var2;
% using above variable
ds2(logical_index).var2;
你现在可以理解为什么MATLAB引入表了嘿嘿。
我整理了函数
function el = struct_pick(s, cdata, cnames, rname)
% Pick an element from a struct by column and row name
coldata = vertcat(s.(cdata));
colnames = mat2cell(vertcat(s.(cnames)), ones(1, length(s)));
% This assumes rname is a string
flt = strcmp(colnames, rname);
el = coldata(logical(flt));
endfunction
用
调用
% Pick an element by column and row name
cdata = 'var3';
cnames = 'idxstr';
rname = 'i01';
elem = struct_pick(ds2, cdata, cnames, rname);
它似乎可以完成这项工作。
我不知道这是否是一种不必要的人为做法。
仍然需要处理行名不是字符串的可能性,如
cnames = 'idx';
rname = 1;
EDIT:如果 idxstr
中的字符串长度不同,则会抛出 error: vertcat: cat: dimension mismatch
。
Ander Biguri 的回答可以处理这种情况。
正如我在评论中提到的,我相信您对这项工作的结构类型有误。您应该拥有一个包含 'array' 字段的结构,而不是一组(有效的单行)结构。 (数字或单元格,视情况而定)。
例如
d = struct(
'idx', [1, 12 ],
'idxstr', {{'i01', 'i12'}},
'var1', [3.5, 6.5],
'var2', [21, 1],
'var3', [5, 3]
);
有了这个结构,你的问题就变得容易处理了:
d.var2( strcmp( 'i01', d.idxstr ) )
% ans = 21
这也比 R / pandas 数据帧功能更具可比性(也可以通过名称和类似大小的数组有效地初始化)。
PS。请仔细注意用于 'idxstr' 字段的语法:有一个包含单个元素的 'outer' 元胞数组,这意味着您只创建一个结构,而不是结构数组。这个单个元素恰好是一个字符串元胞数组,其中此元胞数组与数值数组大小相同(即 'rows' 的数量相同)。
更新
作为对评论的回应,添加 'rows' 应该相当简单。这是一种方法:
function S = addrow( S, R )
FieldNames = fieldnames( S ).'; NumFields = length( FieldNames );
for i = 1 : NumFields,
S.( FieldNames{i} ) = horzcat( S.( FieldNames{i} ), R{i} );
end
end
那么你可以简单地做:
d = addrow( d, {5, 'i011', 2.7, 10, 11} );
也许您可以使用 strcmp
尝试下面的代码
>> [ds2.var2](strcmp('i01',{ds2.idxstr}))
ans = 21
我的意思是用一个结构来保存一个“table”:
% Sample data
% idx idxstr var1 var2 var3
% 1 i01 3.5 21.0 5
% 12 i12 6.5 1.0 3
第一行包含字段名称。 假设我创建了一个结构
ds2 = struct( ...
'idx', { 1, 12 }, ...
'idxstr', { 'i01', 'i12' }, ...
'var1', { 3.5, 6.5 }, ...
'var2', { 21, 1 }, ...
'var3', { 5, 3 } ...
);
如何检索字段 var2
的值,对应于 idxstr
等于 'i01'
的行?
备注:
- 我无法确保
idxstr
个元素的长度始终为 3。 - 理想情况下,我会有一种方法也适用于包含字符串或任何其他类型变量的列
var2
。
PS:我认为
假设 idxstr
可以超过 3 个字符(它总是 3 个字符有一个更短的版本),这就是我想出的(在 MATLAB 上测试过):
logical_index=~cellfun(@isempty,strfind({ds2(:).idxstr},'i01'))
您可以通过以下方式访问变量:
ds2(~cellfun(@isempty,strfind({ds2(:).idxstr},'i01'))).var2;
% using above variable
ds2(logical_index).var2;
你现在可以理解为什么MATLAB引入表了嘿嘿。
我整理了函数
function el = struct_pick(s, cdata, cnames, rname)
% Pick an element from a struct by column and row name
coldata = vertcat(s.(cdata));
colnames = mat2cell(vertcat(s.(cnames)), ones(1, length(s)));
% This assumes rname is a string
flt = strcmp(colnames, rname);
el = coldata(logical(flt));
endfunction
用
调用% Pick an element by column and row name
cdata = 'var3';
cnames = 'idxstr';
rname = 'i01';
elem = struct_pick(ds2, cdata, cnames, rname);
它似乎可以完成这项工作。 我不知道这是否是一种不必要的人为做法。
仍然需要处理行名不是字符串的可能性,如
cnames = 'idx';
rname = 1;
EDIT:如果 idxstr
中的字符串长度不同,则会抛出 error: vertcat: cat: dimension mismatch
。
Ander Biguri 的回答可以处理这种情况。
正如我在评论中提到的,我相信您对这项工作的结构类型有误。您应该拥有一个包含 'array' 字段的结构,而不是一组(有效的单行)结构。 (数字或单元格,视情况而定)。
例如
d = struct(
'idx', [1, 12 ],
'idxstr', {{'i01', 'i12'}},
'var1', [3.5, 6.5],
'var2', [21, 1],
'var3', [5, 3]
);
有了这个结构,你的问题就变得容易处理了:
d.var2( strcmp( 'i01', d.idxstr ) )
% ans = 21
这也比 R / pandas 数据帧功能更具可比性(也可以通过名称和类似大小的数组有效地初始化)。
PS。请仔细注意用于 'idxstr' 字段的语法:有一个包含单个元素的 'outer' 元胞数组,这意味着您只创建一个结构,而不是结构数组。这个单个元素恰好是一个字符串元胞数组,其中此元胞数组与数值数组大小相同(即 'rows' 的数量相同)。
更新
作为对评论的回应,添加 'rows' 应该相当简单。这是一种方法:
function S = addrow( S, R )
FieldNames = fieldnames( S ).'; NumFields = length( FieldNames );
for i = 1 : NumFields,
S.( FieldNames{i} ) = horzcat( S.( FieldNames{i} ), R{i} );
end
end
那么你可以简单地做:
d = addrow( d, {5, 'i011', 2.7, 10, 11} );
也许您可以使用 strcmp
>> [ds2.var2](strcmp('i01',{ds2.idxstr}))
ans = 21