MATLAB: How to operate on comma separated lists

cell arraycomma-separated-listsconcatenationdirhorzcatnon-scalar structurestructstructurevariablesvertcat

How do I work with comma separated lists ? Below I have 3 structures with member MeanIntensity. I want to concatenate all MeanIntensity into another structure member RGB. How can I do that ?
r_data = regionprops(label, image(:,:,1), 'PixelValues', 'MeanIntensity');
g_data = regionprops(label, image(:,:,2), 'PixelValues', 'MeanIntensity');
b_data = regionprops(label, image(:,:,3), 'PixelValues', 'MeanIntensity');
[regions(:).RGB] = [r_data(:).MeanIntensity, g_data(:).MeanIntensity, b_data(:).MeanIntensity)];
I went to concatenate the data to get a 100 x 3 matrix
rgb = [vertcat(r_data(:).MeanIntensity), vertcat(g_data.MeanIntensity), vertcat(b_data.MeanIntensity)]
Now my task is to figure out how to push this into regions(:).RGB. Why does this not work ?
[regions(:).MeanIntensity] = deal([rgb(:,1), rgb(:,2), rgb(:,3)]);
This doesnt work either
[regions(:).MeanIntensity] = [rgb(:,1), rgb(:,2), rgb(:,3)];
how ?

Best Answer

Introduction: Comma separated lists are really very simple. You use them all the time. Here is one:
a,b,c,d
That is a comma separated list containing four variables, the variables a, b, c, and d. Every time you write a list of variables separated by commas then you are writing a comma separated list. Most commonly you would write a comma separated list as inputs when calling a function or operator:
fun(a,b,c,d)
or as the outputs:
[a,b,c,d] = fun();
It is very important to understand that in general a comma separated list is NOT one variable! However sometimes it is useful to create a comma separated list from one variable (or define one variable from a comma-separated list), and MATLAB has two ways of doing this, either using a cell array:
cell_array{:} % all elements

cell_array{idx} % selected elements

struct_array.field % all elements
struct_array(idx).field % selected elements
But both of these are still exactly equivalent to what I wrote at the top: they will generate this:
variable1, variable2, variable3, ...
and they will generate as many variables in that list as the structure or cell array has elements (or that are picked using indexing). A comma-separated list of one is equivalent to one single variable, but otherwise there can be zero, two, three, or more variables. Here is an example showing that a comma separated list generated from a cell array is the same as a comma separated list written individually:
>> C = {1,0,Inf};
>> C{:}
ans =
1
ans =
0
ans =
Inf
>> 1,0,Inf
ans =
1
ans =
0
ans =
Inf
Function Inputs: Remember that every time you call a function with multiple input arguments you are using a comma-separated list:
fun(a,b,c,..)
and this is exactly why they are useful: because you can specify the arguments for a function or operator without knowing anything about the arguments (even how many there are). Using my example above:
>> vertcat(C{:})
ans =
1
0
Inf
which, as we should know by now, is exactly equivalent to writing the same comma separated list directly into the function call:
>> vertcat(1,0,Inf)
ans =
1
0
Inf
How can we use this? Commonly these are used to generate vectors of values from a structure or cell array, e.g. to concatenate the names which are in the output structure of dir:
S = dir(...);
N = {S.name}
which is simply equivalent to
N = {S(1).name, S(2).name, S(3).name, ...}
Or, consider a function with multiple optional input arguments:
opt = {'HeaderLines',2, 'Delimiter',',', 'CollectOutputs',true);
fid = fopen(...);
C = textscan(fid,'%f%f',opt{:});
fclose(fid);
Note how I pass the optional arguments as a comma separated list. Remember how a comma separated list is equivalent to writing var1,var2,var3,..., then the above example is really just this:
C = textscan(fid,'%f%f', 'HeaderLines',2, 'Delimiter',',', 'CollectOutputs',true)
with the added advantage that I can specify all of the optional arguments elsewhere and handle them as one cell array (e.g. as a function input, or at the top of the file). Or I could select which options I want simply by using indexing on that cell array. Note that varargin and varargout can also be useful.
Function Outputs: In much the same way that the input arguments can be specified, so can an arbitrary number of output arguments. This is commonly used for functions which return a variable number of output arguments, e.g. ndgrid and ind2sub. For example we can easily get all outputs of ndgrid, for any number of inputs (in this example three inputs and outputs):
C = {1:3,4:7,8:9};
[C{:}] = ndgrid(C{:});
which is thus equivalent to:
[C{1},C{2},C{3}] = ndgrid(C{1},C{2},C{3});
Your Examples: Lets have a look at your examples in more detail:
r_data(:).MeanIntensity
We now know that this is a shorthand way to write this:
r_data(1).MeanIntensity, r_data(2).MeanIntensity, r_data(3).MeanIntensity, ...
and so you can use it anywhere that you would want a list of variables: inputs to a functions or an operator. One common application with a concatenation operator (the colon you used is not necessary if you want all elements: you can use indexing if you want a subset of the elements):
vertcat(r_data.MeanIntensity)
is equivalent to writing
vertcat(r_data(1).MeanIntensity, r_data(2).MeanIntensity, r_data(3).MeanIntensity, ... )
Summary: Just remember that in general a comma separated list is not one variable, and that they are exactly what they say: a list (of variables) separated with commas. You use them all the time without even realizing it, every time you write this:
fun(a,b,c,d)