MATLAB Answers

How to find the largest index into a cell array, pointing to an element after which all subsequent elements are empty?

1 view (last 30 days)
Minh Tran
Minh Tran on 18 Sep 2018
Commented: Minh Tran on 18 Sep 2018
I'm writing a function that parses a text file containing key-value-value tuples that are separated by 2 delimiters. The second delimiter is optional. Each 3-tuple is separated by a newline. The output array of size M x 3 (for a text file containing M key-value-value tuples) must not containing unused (empty) cell arrays.
ML_Configfile.jpg shows what a config file looks like (delimiter is the colon).
ML_matvalues.jpg indicates what the output values `keys`, `values`, `units` look like when ran with that text file as input.
ML_End.jpg shows what the output looks like before some lines of my code executes to remove empty, preallocated cells. In this case, cells below 55 needs to be removed.
Here is the function:
function [options_array, keys, values, units] = parseconfig(config_filename, delimiter, max_num_lines)
% case_1 = ''
% case_2 = '::'
% case_3 = ' : : '
% case_4 = 'System_Name : Santos Basin'
% case_5 = 'Look_Back_End : 0.0 : days'
% case_5 = 'Speed_Threshold : 3.0 : knots % This is an inline comment'
% case_6 = 'Author : "Johnny Appleseed"'
% case_7 = '%This is an inline comment'
% case_8 = '%Bad comment : '
% case_9 = ': %Bad comment : '
% case_10 = 'ValidField : %Bad comment : '
% case_11 = 'ValidField : ValidValue : %Bad comment'
% Preallocate cell array for each key-value pair
keys = cell(max_num_lines, 1);
values = cell(max_num_lines, 1);
units = cell(max_num_lines, 1);
line_number = 1;
fh = fopen(config_filename, 'r');
while (line_number <= max_num_lines)
line = fgetl(fh);
if (isempty(line)) continue, end
if (~ischar(line)), break, end
fields = textscan(line, '%s%s%[^%]', ...
'Delimiter', delimiter, 'CommentStyle', '%');
[fieldname, fieldvalue, fieldunit] = fields{:};
% Append trimmed values to their return cell arrays
if ~isempty(strtrim(fieldname))
keys{line_number} = strtrim(fieldname);
values{line_number} = strtrim(fieldvalue);
units{line_number} = strtrim(fieldunit);
line_number = line_number + 1;
% Find the greatest index of last-occuring empty cell array of
% `fieldnames`, `fieldvalues`, and `fieldunits`
% Locate & delete unused, preallocated cells (reshaping cell array)
keys = keys(~cellfun('isempty', keys));
values = values(~cellfun('isempty', values));
units = units(~cellfun('isempty', units));
% Output array
options_array = [keys values units];
The issue with
keys = keys(~cellfun('isempty', keys));
values = values(~cellfun('isempty', values));
units = units(~cellfun('isempty', units));
is that it doesn't preserve the empty cells in column 3 (`units`) when the delimiter is omitted in the text file. So if I somehow found the largest index pointing to the start of the empty cell array elements, I can slice-out the empty cell array elements from each of the three cell arrays.


Sign in to comment.

Accepted Answer

ADragon on 18 Sep 2018
I think find() will help you get what you want
idx1 = find(~cellfun('isempty',keys),1,'last');
idx2 = find(~cellfun('isempty',values),1,'last');
idx3 = find(~cellfun('isempty',units),1,'last');
lastidx = max([idx1 idx2 idx3]);

  1 Comment

Minh Tran
Minh Tran on 18 Sep 2018
Thanks although I realized that I'd kept a counter for the number of keys and that that could just serve as the index from which to delete the unused preallocated cell array:
keys( (line_number + 1):end,:) = [];
values( (line_number + 1):end,: ) = [];
units( (line_number + 1):end,:) = [];
My solution isn't explicitly clear but it's good to know I can alternatively use find().

Sign in to comment.

More Answers (0)




Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by