Cap*_*rog 29 matlab struct find
我有一个包含数千个数据样本的结构.每个数据点包含多个对象.例如:
Structure(1).a = 7
Structure(1).b = 3
Structure(2).a = 2
Structure(2).b = 6
Structure(3).a = 1
Structure(3).b = 6
...
... (thousands more)
...
Structure(2345).a = 4
Structure(2345).b = 9
Run Code Online (Sandbox Code Playgroud)
... 等等.
如果我想找到包含数字6的所有'.b'对象的索引号,我希望以下函数可以解决这个问题:
find(Structure.b == 6)
Run Code Online (Sandbox Code Playgroud)
......我希望答案包含'2'和'3'(对于上面显示的输入).
但是,这不起作用.什么是正确的语法和/或我可以首先以更合理的方式安排我的数据?
Eit*_*n T 24
语法Structure.b为结构的数组给你一个逗号分隔的列表,所以你必须将它们串联所有的(例如,使用括号[]),以获得一个向量:
find([Structure.b] == 6)
Run Code Online (Sandbox Code Playgroud)
对于上面显示的输入,结果如预期:
ans =
2 3
Run Code Online (Sandbox Code Playgroud)
正如Jonas所指出的,只有在没有包含空矩阵的字段时才会起作用,因为空矩阵不会反映在连接结果中.
如果您怀疑这些字段可能包含空矩阵,请将它们转换为NaNs(如果可能的话......)或考虑使用Rody建议的更安全的解决方案之一.
另外,我已经想到了使用字符串的另一个有趣的解决方法.我们可以将所有内容连接成一个分隔的字符串,以保存有关空字段的信息,然后将其标记回来(在我看来,这在MATLAB中比在处理存储在单元格中的数值更容易完成).
受Jonas评论的启发,我们可以将空字段转换成NaN如下:
str = sprintf('%f,', Structure.b)
B = textscan(str, '%f', 'delimiter', ',', 'EmptyValue', NaN)
Run Code Online (Sandbox Code Playgroud)
这允许您申请find以下内容B:
find(B{:} == 6)
ans =
2
3
Run Code Online (Sandbox Code Playgroud)
基于EitanT对Jonas评论的回答,一种更安全的方式可能是
>> S(1).a = 7;
S(1).b = 3;
S(2).a = 2;
S(2).b = 6;
S(3).a = 1;
S(3).b = [];
S(4).a = 1;
S(4).b = 6;
>> find( cellfun(@(x)isequal(x,6),{S.b}) )
ans =
2 4
Run Code Online (Sandbox Code Playgroud)
虽然它可能不是很快(与EitanT的版本相比),所以只在需要时使用它.
这个问题的另一个答案!这次,我们将比较以下4种方法的性能:
测试代码:
% Set up test
N = 1e5;
S(N).b = [];
for ii = 1:N
S(ii).b = randi(6); end
% Rody Oldenhuis 1
tic
sol1 = find( cellfun(@(x)isequal(x,6),{S.b}) );
toc
% EitanT 1
tic
sol2 = find([S.b] == 6);
toc
% EitanT 2
tic
str = sprintf('%f,', S.b);
values = textscan(str, '%f', 'delimiter', ',', 'EmptyValue', NaN);
sol3 = find(values{:} == 6);
toc
% Rody Oldenhuis 2
tic
ids = false(N,1);
for ii = 1:N
ids(ii) = isequal(S(ii).b, 6);
end
sol4 = find(ids);
toc
% Rody Oldenhuis 3
tic
idx = false(size(S));
SS = {S.b};
inds = ~cellfun('isempty', SS);
idx(inds) = [SS{inds}]==6;
sol5 = find(idx);
toc
% make sure they are all equal
all(sol1(:)==sol2(:))
all(sol1(:)==sol3(:))
all(sol1(:)==sol4(:))
all(sol1(:)==sol5(:))
Run Code Online (Sandbox Code Playgroud)
我工作的机器上的结果(AMD A6-3650 APU(4核),4GB RAM,Windows 7 64位):
Elapsed time is 28.990076 seconds. % Rody Oldenhuis 1 (cellfun)
Elapsed time is 0.119165 seconds. % EitanT 1 (no empties)
Elapsed time is 22.430720 seconds. % EitanT 2 (string manipulation)
Elapsed time is 0.706631 seconds. % Rody Oldenhuis 2 (loop)
Elapsed time is 0.207165 seconds. % Rody Oldenhuis 3 (vectorized)
ans =
1
ans =
1
ans =
1
ans =
1
Run Code Online (Sandbox Code Playgroud)
在我的Homebox上(AMD Phenom(tm)II X6 1100T(6核),16GB RAM,Ubuntu64 12.10):
Elapsed time is 0.572098 seconds. % cellfun
Elapsed time is 0.119557 seconds. % no emtpties
Elapsed time is 0.220903 seconds. % string manipulation
Elapsed time is 0.107345 seconds. % loop
Elapsed time is 0.180842 seconds. % cellfun-with-string
Run Code Online (Sandbox Code Playgroud)
得爱JIT :)
哇...有谁知道为什么这两个系统的行为如此不同?
此外,鲜为人知的事实 - cellfun其中一个可能的字符串参数非常快(这表明匿名函数需要多少开销......).
尽管如此,如果你可以绝对确定没有空箱,那么请选择EitanT的原始答案; 这就是Matlab的用途.如果你不能确定,那就去循环吧.