Search code examples
matlabstructprintfoctavecell-array

formatted print of structures contents and fieldnames in matlab/octave


I need to print to command window the contents of a structure with corresponding field names and some text around every structure element.

i.e. This something [fieldname(i)] has the value of [struct.fieldname(i) value] something.

After half a day of headache I ended up with an expression (which does not work) and a loop (which works).

Question - is there a way to do this without a loop?

Code:

box.apples = 25
box.cherries = 0.5
box.iron = 0.085

% Loop method (works)
for i = (1:length(struct2cell(box))) ;
    printf('There are %.3f kg of %s in the box \n', struct2cell(box){i}, fieldnames(box){i})
end
% Single expression method (doesn't work)
printf('There are %.3f kg of %s in the box \n', struct2cell(box){:}, fieldnames(box){:})

The loop returns a sensible output exactly as I want:

There are 25.000 kg of apples in the box 
There are 0.500 kg of cherries in the box
There are 0.085 kg of iron in the box

Just the printf expression however returns this weird output:

There are 25.000 kg of  in the box
There are 0.085 kg of apples in the box
There are 99.000 kg of herries in the box
There are 105.000 kg of ron in the box

Advice appreciated


Solution

  • Just adding my 2¢ to the above answers.

    "Without a loop" is not necessarily always faster. Especially now with matlab's JIT-compiler for loops. So don't just avoid loops and end up with ugly-looking code-golf just for the sake of having a one-liner. Not to mention, one-liners do not necessarily equal vectorisation. If in doubt about speed, do a simple test-case benchmark.

    Furthermore loops are generally much more readable, so unless you get a massive speedup from avoiding it, it's generally not necessarily worth sacrificing readability for the sake of micro-optimisations.

    Having said that, here's how I would have written that loop:

      for CellStr = fieldnames(box).'
        Name = CellStr{1};
        fprintf('There are %.3f kg of %s in the box\n', box.(Name), Name)
      end
    

    Or, if you're using octave, octave specifically provides the following lovely syntax:

    for [Val, Field] = box
      fprintf('There are %.3f kg of %s in the box\n', Val, Field)
    end
    

    Some benchmarks on my machine (octave, no JIT compilation, time elapsed after 10000 iterations):

    one-liner in answers above = 0.61343 seconds
    top loop shown above       = 0.92640 seconds
    bottom loop shown above    = 0.41643 seconds <-- wins
    loop shown in the question = 1.6744  seconds
    

    So, see, in this particular case, one of the for-loop approaches is in fact faster than the one-liner approach.


    Also note that box is the name of a function in matlab / octave; it's generally a bad idea to use variable names that shadow builtin functions. You can generally get around that by using Capital letters for variables, or simply look for a function by that name before calling your variable that