A customer recently asked me this question at the MATLAB Virtual Conference.
Contents
Question about Summing Cell Rows
I was hoping you would cover cells some day. Here is a particular problem I was hoping to have a more elegant solutions for.
A is a cell that has String (say names) in the first column, Numbers (say scores in tests 1 and 2) in the next two columns. Assume that each cell has only one value. Is there an easier way to calculate, say the sum of the two test scores than a for loop?
Example
Let's make some sample data.
c(1:4,1) = {'Fred' 'Alice' 'Lucy' 'Tom'};
c(1:4,2) = { 90 80 55 102 };
c(1:4,3) = { 43 91 80 44 }c =
'Fred' [ 90] [43]
'Alice' [ 80] [91]
'Lucy' [ 55] [80]
'Tom' [102] [44]
Answer
To sum the entries in a row for this cell array, I can simply turn the numeric values into a numeric array via comma-separated list notation, and then sum the rows. Let's see the pieces for clarity. Here's the comma-separated list.
c{:,2:3}ans =
90
ans =
80
ans =
55
ans =
102
ans =
43
ans =
91
ans =
80
ans =
44
Now place the results into a vector.
vec = [c{:,2:3}]vec =
90 80 55 102 43 91 80 44
Reshape the vector appropriately into a matrix.
array = reshape(vec,[],2)
array =
90 43
80 91
55 80
102 44
Now sum the results along the rows.
tot = sum(array,2)
tot = 133 171 135 146
Or, in one bigger statement, try this.
tot = sum(reshape([c{:,2:3}],[],2),2)tot = 133 171 135 146
Cell Array Questions
Do you use cell arrays? Can you do what you want without undo contortions? Let me know here.
Get
the MATLAB code
Published with MATLAB® 7.9



You can also do:
sum(cell2mat(c(:,2:3)),2)
-Tomasz
This is not as easily generalizable, but maybe simpler for this simple case:
tot = cellfun(@plus,c(:,2),c(:,3))
I use cell arrays all the time, and yes, sometimes there is a lot of coding acrobatics that takes place when dealing with them.
dear loren
almost everything can be done using CELLFUN - although, this approach does not always yield the fastest solution…
totc=cellfun(@(x,y) sum([x,y],2),c(:,2),c(:,3));
also, one should not forget the CAT command, which is slightly more versatile than the […] solution…
just a thought…
best
urs
Thanks for the other solutions. They are nice and work just fine.
Personal preference: I prefer to not use cellfun when there are other ways that aren’t too tortuous. Likewise with cell2mat, vs. extracting the values syntactically. Maybe it’s because the next thing I often need to do requires more generalization. Or maybe I’m being perverse and the other ways are more readable/maintainable. It’s possible that there might be performance differences though they won’t matter here much if the arrays are small.
Chacun à son goût,
–Loren
I’ve been working with cells more and more to use the xlswrite function. Is there a quick way to concatenate values from a matrix onto an existing cell? Say, for instance, I wanted to add another column from the values of
m=[1;2;3;4];
to the cell array c in your post.
Dan C-
Try this:
c(1:4,1) = {'Fred' 'Alice' 'Lucy' 'Tom'}; c(1:4,2) = { 90 80 55 102 }; c(1:4,3) = { 43 91 80 44 } m=[1;2;3;4] cm = mat2cell(m,ones(size(m)),1) c(:,end+1) = cm–loren
Loren,
I like this alternate syntax instead of your last line of code to Dan C.
(I hope I get the
I’ve always wished that cell2mat had the equivalent syntax as mat2cell or num2cell, i.e. being able to combine cell arrays along only one dimension, or into specifically-sized new cells. For example, take a 3 x 2 cell array, with each cell holding a 4 x 5 array, and concatenate along rows only into a 3 x 1 cell array with 4 x 10 elements.
I’ve written a little function for the task since I need it so often (you can do it with a few loops pretty easily).
I use cells whenever I feel they are necessary/helpful. That is quite often. Sometimes things do get tricky though.
In order to avoid unnecessary acrobatics I try to store my data so that it is easy to use. The data in the example above I would save in a struct of a cell and a matrix:
c =
name: {’Fred’ ‘Alice’ ‘Lucy’ ‘Tom’}
data: [2×4 double]
This is actually how I arrange most of my data, sometimes 3-d matrices and additional fields or whatever. But I try to keep the numerical data in matrices, the MATLAB way.
Hi,
I find deal() can normally solve problems like this, leaving code looking cleaner but perhaps a bit obscure, e.g.
[c{:,end+1}] = deal(m)OysterEngineer-
Your code works well too.
Kelly-
I hope you’ve placed your code on the File Exchange!
Pekka-
Good point about the data, but I was given the form of the dataset initially. People should definitely think about how to best store the data early in the development process.
Greg S.-
I don’t think deal is doing what you want here. It is placing the entire array m in each cell in the final column of c.
–Loren
Thank you for addressing cells. I always feel a little lost whenever I try to use them.
Loren,
I’m looking for an elegant, and generalized way to sum each cell in a cell array of different sized matrices, without looping. Surely there must be a way?
e.g.:
a = {rand(3,1),rand(7,1),rand(5,1)}creates a 3 cell array with different length matrixes. how can I find the sum of each of theses cells in one command that returns a 3×1 matrix with the sum of each cell as an element in the vector?
Mark-
Take a look at cellfun and think about using the function sum. Like this…
>> a = {rand(3,1),rand(7,1),rand(5,1)} ; >> cellfun(@sum,a,'UniformOutput',true) ans = 1.8475 4.3911 3.3710–Loren
Hi Loren,
Why does the following not work?
data_classwise = [19x121 double] [19x134 double] [19x84 double] [19x107 double] c = cell2mat(data_classwise); mat2cell(cc,[19 121],[19 134],[19 84],[19 107]) ??? Error using ==> mat2cell at 96 Number of input vector arguments, 4, does not match the input matrix's number of dimensions, 2.I am looking at converting a cell( 4, 2 dimensional matrixes) to a single matrix, and then covert this back to cells using mat2cell().
2) If i need to know the size of the individual matrices within the cell can i use cellfun() for this?
Thanks!
sorry, in the previous code
mat2cell(c,[19 121],[19 134],[19 84],[19 107])
Kishore-
It is not clear to me what you are trying to actually achieve. If you want to concatenate the 4 cells, you can do this.
mymatrix = cat(2, data_classwise {:}); whos mymatrix Name Size Bytes Class Attributes mymatix 19x446 67792 doubleIf this is not what you want, I suggest you read the error message carefully and look at the help for mat2cell carefully as well.
–Loren
Hi Loren,
I was wondering if there was a way to pre-allocate cell arrays for iteration. I’ve been playing around with this for a while and haven’t figured out a way to do it.
Sumedh-
It depends what you want to preallocate the cells to. You can use deal, e.g., to initialize all cells to the same value.
[c{1:5}] = deal(initialValue);You can also use deal to initialize the cells to different values, using a cell array as a comma separated list as the input to deal.
There are other ways. I suggest you read more of the blogs in the category of cell arrays. Variants for initializing the cells are covered in them.
–Loren
Thanks Loren, found a way out.
Thanks Loren, “deal” is what I was looking for.
Question: Array1={'AA','AB','BB','BA'}; It has unique element. Array2={'AA','AB','AA','BA','BA','BB','AB'}; All its elements come from Array1. I want to get a vector whose length is same as Array2,and its contents are the index of elements in Array1, and its every element corresponds to the elements in Array2. For the above two arrays, my result vector should be like [1 2 1 4 4 3 1]. How can I get it without using loop? Thank you very much!!!Jun-
ismember is your friend here:
>> [aa,ind] = ismember(Array2,Array1) aa = 1 1 1 1 1 1 1 ind = 1 2 1 4 4 3 2–Loren