Reputation: 217
I actually have a text file containing uint8 data like this:
[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
What I ultimately want is a struct, say A
, with fields containing this data as:
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]
So what the above example shows is to find the multiple instances of the matrix and stack them into one. If there is a space in the name, remove the space or replace that with underscore.
Until now, I have:
A = importdata('file.txt');
which creates a cell array (20,000 x 1 for my original data) containing the data. I know the names of the matrices already that the text file will have. So I tried to differentiate the matrices like the following which gives me the cell containing the matrices and its name:
A(~cellfun(@isempty, strfind(A,'bl')))
How do I proceed? Or What would be a simpler solution to this problem with more speed?
Upvotes: 2
Views: 75
Reputation: 30047
You could use textscan
as gnovice suggested to read the data
fid = fopen('file.txt');
data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
fclose(fid);
values = data{1};
fields = data{2};
Then use a simple loop to create the struct, since you can access a field of a struct by a string using round brackets
% demo for accessing fields
myStruct.myField
% is equivalent to
myStruct.('myField')
So:
% 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
Upvotes: 1
Reputation: 125854
I would use textscan
instead of importdata
in this case, since you're dealing with mixed data types:
fid = fopen('file.txt');
data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
fclose(fid);
values = data{1};
fields = data{2};
Which gives you the following results in values
and 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'
Now you can replace spaces in fields
with underscores using 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, ~, index] = unique(strrep(fields, ' ', '_'));
counts = accumarray(index, 1);
[~, sortIndex] = sort(index);
values = mat2cell(values(sortIndex, :), counts);
Now you can easily put it all together into a structure using 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]
Upvotes: 4
Reputation: 549
If your file is rather long, well formatted and you don't want to use awful things with eval, I'd recommend using old style of setting structure field via 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);
Upvotes: 1