从包含矩阵及其名称的字符串创建结构
Making a struct from a string containing matrices and its names
我实际上有一个包含 uint8 数据的文本文件,如下所示:
[0, 18, 121] bl
[0, 19, 12] gt
[24, 19, 22] apa
[0, 18, 1] bl
[24, 19, 22] apa bpa
[1, 2, 3] apa
我最终想要的是一个结构,比如 A
,其中包含此数据的字段为:
A.bl= [0, 18, 121;
0, 18, 1 ];
A.gt = [0, 19, 12];
A.apa = [24,19,22];
A.apa_bpa = [24,19, 22] or A.apabpa= [24, 19, 22]
所以上面的例子展示的是找到矩阵的多个实例并将它们堆叠为一个。如果名称中有 space,请删除 space 或将其替换为下划线。
到目前为止,我有:
A = importdata('file.txt');
创建一个包含数据的元胞数组(我的原始数据为 20,000 x 1)。我已经知道文本文件将具有的矩阵的名称。所以我试着像下面这样区分矩阵,它给了我包含矩阵及其名称的单元格:
A(~cellfun(@isempty, strfind(A,'bl')))
我该如何进行?或者有什么更简单的解决方案可以更快地解决这个问题?
如果您的文件相当长,格式良好并且您不想在 eval 中使用糟糕的东西,我建议您使用通过 setfield 设置结构字段的旧样式
% I just copied data from top of the post to the document
fid = fopen('testdoc.txt');
store_struct = struct();
while ~feof(fid)
tmp_line = fgetl(fid);
delim_idx = find(tmp_line == ']');
tmp_mat=uint8(str2num(tmp_line(2:delim_idx-1)));
tmp_field = deblank(tmp_line(delim_idx+2:length(tmp_line)));
tmp_field(tmp_field == ' ') = '_';
if isfield(store_struct,tmp_field)
store_struct = setfield(store_struct,tmp_field,...
[getfield(store_struct,tmp_field);tmp_mat]);
else
store_struct = setfield(store_struct,tmp_field,...
tmp_mat);
end
end
fclose(fid);
在这种情况下我会使用 textscan
instead of importdata
,因为您处理的是混合数据类型:
fid = fopen('file.txt');
data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
fclose(fid);
values = data{1};
fields = data{2};
在 values
和 fields
中得到以下结果:
values =
6×3 int32 matrix
0 18 121
0 19 12
24 19 22
0 18 1
24 19 22
1 2 3
fields =
6×1 cell array
'bl'
'gt'
'apa'
'bl'
'apa bpa'
'apa'
现在您可以使用 strrep
, find the unique strings with unique
, get the number of repeats of each string with accumarray
, sort the rows of values
to match the list of unique field names, and group rows of values
using mat2cell
:
将 fields
中的空格替换为下划线
[fields, ~, index] = unique(strrep(fields, ' ', '_'));
counts = accumarray(index, 1);
[~, sortIndex] = sort(index);
values = mat2cell(values(sortIndex, :), counts);
现在您可以使用 cell2struct
:
轻松地将它们组合成一个结构
S = cell2struct(values, fields)
S =
struct with fields:
apa: [2×3 int32]
apa_bpa: [24 19 22]
bl: [2×3 int32]
gt: [0 19 12]
您可以按照 gnovice 的建议使用 textscan
来读取数据
fid = fopen('file.txt');
data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
fclose(fid);
values = data{1};
fields = data{2};
然后使用一个简单的循环来创建结构,因为您可以使用圆括号通过字符串访问结构的字段
% demo for accessing fields
myStruct.myField
% is equivalent to
myStruct.('myField')
所以:
% Replace spaces with underscores in 'fields'
fields = strrep(fields, ' ', '_');
% Initialise struct
A = struct;
% Loop over fields, assign values
for ii = 1:numel(fields)
if isfield(A,fields{ii})
% Append to array if field already exists
A.(fields{ii}) = [A.(fields{ii}); values(ii,:)];
else
% Create field as array if doesn't yet exist
A.(fields{ii}) = values(ii,:);
end
end
我实际上有一个包含 uint8 数据的文本文件,如下所示:
[0, 18, 121] bl
[0, 19, 12] gt
[24, 19, 22] apa
[0, 18, 1] bl
[24, 19, 22] apa bpa
[1, 2, 3] apa
我最终想要的是一个结构,比如 A
,其中包含此数据的字段为:
A.bl= [0, 18, 121;
0, 18, 1 ];
A.gt = [0, 19, 12];
A.apa = [24,19,22];
A.apa_bpa = [24,19, 22] or A.apabpa= [24, 19, 22]
所以上面的例子展示的是找到矩阵的多个实例并将它们堆叠为一个。如果名称中有 space,请删除 space 或将其替换为下划线。
到目前为止,我有:
A = importdata('file.txt');
创建一个包含数据的元胞数组(我的原始数据为 20,000 x 1)。我已经知道文本文件将具有的矩阵的名称。所以我试着像下面这样区分矩阵,它给了我包含矩阵及其名称的单元格:
A(~cellfun(@isempty, strfind(A,'bl')))
我该如何进行?或者有什么更简单的解决方案可以更快地解决这个问题?
如果您的文件相当长,格式良好并且您不想在 eval 中使用糟糕的东西,我建议您使用通过 setfield 设置结构字段的旧样式
% I just copied data from top of the post to the document
fid = fopen('testdoc.txt');
store_struct = struct();
while ~feof(fid)
tmp_line = fgetl(fid);
delim_idx = find(tmp_line == ']');
tmp_mat=uint8(str2num(tmp_line(2:delim_idx-1)));
tmp_field = deblank(tmp_line(delim_idx+2:length(tmp_line)));
tmp_field(tmp_field == ' ') = '_';
if isfield(store_struct,tmp_field)
store_struct = setfield(store_struct,tmp_field,...
[getfield(store_struct,tmp_field);tmp_mat]);
else
store_struct = setfield(store_struct,tmp_field,...
tmp_mat);
end
end
fclose(fid);
在这种情况下我会使用 textscan
instead of importdata
,因为您处理的是混合数据类型:
fid = fopen('file.txt');
data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
fclose(fid);
values = data{1};
fields = data{2};
在 values
和 fields
中得到以下结果:
values =
6×3 int32 matrix
0 18 121
0 19 12
24 19 22
0 18 1
24 19 22
1 2 3
fields =
6×1 cell array
'bl'
'gt'
'apa'
'bl'
'apa bpa'
'apa'
现在您可以使用 strrep
, find the unique strings with unique
, get the number of repeats of each string with accumarray
, sort the rows of values
to match the list of unique field names, and group rows of values
using mat2cell
:
fields
中的空格替换为下划线
[fields, ~, index] = unique(strrep(fields, ' ', '_'));
counts = accumarray(index, 1);
[~, sortIndex] = sort(index);
values = mat2cell(values(sortIndex, :), counts);
现在您可以使用 cell2struct
:
S = cell2struct(values, fields)
S =
struct with fields:
apa: [2×3 int32]
apa_bpa: [24 19 22]
bl: [2×3 int32]
gt: [0 19 12]
您可以按照 gnovice 的建议使用 textscan
来读取数据
fid = fopen('file.txt');
data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
fclose(fid);
values = data{1};
fields = data{2};
然后使用一个简单的循环来创建结构,因为您可以使用圆括号通过字符串访问结构的字段
% demo for accessing fields
myStruct.myField
% is equivalent to
myStruct.('myField')
所以:
% Replace spaces with underscores in 'fields'
fields = strrep(fields, ' ', '_');
% Initialise struct
A = struct;
% Loop over fields, assign values
for ii = 1:numel(fields)
if isfield(A,fields{ii})
% Append to array if field already exists
A.(fields{ii}) = [A.(fields{ii}); values(ii,:)];
else
% Create field as array if doesn't yet exist
A.(fields{ii}) = values(ii,:);
end
end