× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS

Merging elements of different cells

Ray Phan
Jul 09, 2015
<p>Assuming that each cell has two rows and a variable amount of columns where the first row is the ID and the second row is an attribute, I'd consolidate all of the cells into a single 2D matrix and use <a href="http://www.mathworks.com/help/matlab/ref/accumarray.html" rel="nofollow"><code>accumarray</code></a>. <code>accumarray</code> is very suitable here because you want to group values that belong to the same ID together and apply a function to it. In our case, our function will simply place the values in a cell array and we'll make sure that the values are sorted because the values that are grouped by <code>accumarray</code> per ID come into the function in random order. </p> <p>Use <a href="http://www.mathworks.com/help/matlab/ref/cell2mat.html" rel="nofollow"><code>cell2mat</code></a> to convert the cells into a 2D matrix, transpose it so that it's compatible for <code>accumarray</code>, and use it. One thing I'll need to note is that should any IDs be missing, <code>accumarray</code> will make this slot empty. What I meant by missing is that in your example, the ID 4 is missing as there is a gap between 3 and 5 and also the ID 6 between 5 and 7 (I added the example in your comment to me). Because the largest ID in your data is 7, <code>accumarray</code> works by assigning outputs from ID 1 up to ID 7 in increments of 1. The last thing we would need to tackle is to eliminate any empty cells from the output of <code>accumarray</code> to complete the grouping.</p> <p>BTW, I'm going to assume that your cell array consists of a <strong>single</strong> row of cells like your example.... so:</p> <pre><code>%// Setup A{1,1}=[1 2;2 4]; A{1,2}=[2 3 5;8 5 6]; A{1,3}=[7;8]; %// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray B = cell2mat(A).'; %// Group IDs together and ensure they're sorted out = accumarray(B(:,1), B(:,2), [], @(x) {sort(x)}); %// Add a column of IDs and concatenate with the previous output IDs = num2cell((1:numel(out)).'); out = [IDs out]; %// Any cells from the grouping that are empty, eliminate ind = cellfun(@isempty, out(:,2)); out(ind,:) = []; </code></pre> <p>We get:</p> <pre><code>out = [1] [ 2] [2] [2x1 double] [3] [ 5] [5] [ 6] [7] [ 8] &gt;&gt; celldisp(out(2,:)) ans{1} = 2 ans{2} = 4 8 </code></pre> <hr> <p>If you'd like this done on a 2D cell array, where each row of this cell array represents a separate instance of the same problem, one suggestion I have is to perhaps loop over each row. Something like this, given your example in the comments:</p> <pre><code>%// Setup A{1,1}=[1 2;2 4]; A{1,2}=[2 3 5;8 5 6]; A{1,3}=[7;8]; A{2,1}=[1 2;2 4]; A{2,2}=[1;7]; %// Make a cell array that will contain the output per row out = cell(size(A,1),1); for idx = 1 : size(A,1) %// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray B = cell2mat(A(idx,:)).'; %// Group IDs together and ensure they're sorted out{idx} = accumarray(B(:,1), B(:,2), [], @(x) {sort(x)}); %// Add a column of IDs and concatenate with the previous output IDs = num2cell((1:numel(out{idx})).'); out{idx} = [IDs out{idx}]; %// Any cells from the grouping that are empty, eliminate ind = cellfun(@isempty, out{idx}(:,2)); out{idx}(ind,:) = []; end </code></pre> <p>We get:</p> <pre><code>&gt;&gt; out{1} ans = [1] [ 2] [2] [2x1 double] [3] [ 5] [5] [ 6] [7] [ 8] &gt;&gt; out{2} ans = [1] [2x1 double] [2] [ 4] &gt;&gt; celldisp(out{1}(2,:)) ans{1} = 2 ans{2} = 4 8 &gt;&gt; celldisp(out{2}(1,:)) ans{1} = 1 ans{2} = 2 7 </code></pre> <p>This tip was originally posted on <a href="http://stackoverflow.com/questions/31217436/Merging%20elements%20of%20different%20cells/31217533">Stack Overflow</a>.</p>
comments powered by Disqus