Merging adjacent cells in a cell array and applying rules to remove entries
Show older comments
I have a cell array with cells of different sizes, for instance:
([-2, -1], [1, -2]; [1, -2], [2]; [1, -2, -1], [1, 2]). I would like to merge the cells in each row, so that I get:
([-2, -1, 1, -2]; [1, -2, 2]; [1, -2, -1, 1, 2]).
I would then like to perform an operation where, within each cell, if two consecutive numbers are equal in size but opposite in sign then they are both removed, e.g. [-2, -1, 1, -2] becomes [-2, -2], and [1, -2, -1, 1, 2] becomes [1, -2, 2], then becomes [1] (through a double application of this operation). So, my final cell array becomes: ([-2, -2]; [1]; [1]).
Any suggestions on how to accomplish these feats?
Answers (3)
Benjamin
on 16 Aug 2016
I'm sure there is a more efficient way, but this gets the job done:
a = {[-2, -1], [1, -2]; [1, -2], [2]; [1, -2, -1], [1, 2]};
output = cell(1);
% go thru each row of cell array
for iRow = 1:size(a,1)
% covert row to numerical array
temp = cell2mat(a(iRow,:));
flag = true;
while flag
Break = false;
% go thru each element
for iNum = 1:length(temp)
num = temp(iNum);
% see if there is a match
toRemove = find(temp == -num);
if ~isempty(toRemove)
% remove the matched elements
toRemove = [iNum,toRemove];
temp(toRemove) = [];
% need to get out of for loop since temp size has changed
Break = true;
break
end
end
if Break
continue
end
% store corrected array
output(end+1,1) = {temp};
flag = false;
end
end
output = output(2:end);
6 Comments
Guillaume
on 16 Aug 2016
Much simpler:
a = {[-2, -1], [1, -2]; [1, -2], [2]; [1, -2, -1], [1, 2]};
mergeda = cell(size(a, 1), 1);
filtereda = cell(size(a, 1), 1);
for row = 1:size(a, 1)
rowcontent = cell2mat(a(row, :));
mergeda{row} = rowcontent;
isopposite = rowcontent(2:end) == -rowcontent(1:end-1);
rowcontent([false, isopposite] | [isopposite, false]) = [];
filtereda{row} = rowcontent;
end
Benjamin
on 16 Aug 2016
this doesn't get the desired result though...the last cell in yours is [1 -2 2] rather than [1]. you're not comparing the first and last elements to each other.
Guillaume
on 16 Aug 2016
Oh! I missed that the filtering was to be reapplied until no more elements could be removed. Easy fix:
a = {[-2, -1], [1, -2]; [1, -2], [2]; [1, -2, -1], [1, 2]};
mergeda = cell(size(a, 1), 1);
filtereda = cell(size(a, 1), 1);
for row = 1:size(a, 1)
rowcontent = cell2mat(a(row, :));
mergeda{row} = rowcontent;
isopposite = rowcontent(2:end) == -rowcontent(1:end-1);
while any(isopposite)
rowcontent([false, isopposite] | [isopposite, false]) = [];
isopposite = rowcontent(2:end) == -rowcontent(1:end-1);
end
filtereda{row} = rowcontent;
end
Benjamin
on 16 Aug 2016
nice!
Guillaume: but it does not provide the correct output: "my final cell array becomes: ([-2, -2]; [1]; [1])"
>> filtereda{:}
ans =
-2 -2
ans =
1
ans =
1 -2 2
See my answer for simple code that provides the correct output.
Guillaume
on 16 Aug 2016
Stephen, you must have missed my new comment which fixed the problem (and is essentially the same as your answer)
Bhavesh Bhatt
on 16 Aug 2016
I hope this is what you are looking for -
cell1 = {[-2,-1],[1, -2]; [1 -2], [2]; [1,-2, -1],[1,2]};
no_of_iterations = 2;
[r c] = size (cell1);
for i = 1:r
cell1{i,1} = [ cell1{i,1:c}] ; % Combine the elements
end
cell1(:,2:end) = []; % Delete the unwanted columns
for k = 1:no_of_iterations
c1 = cellfun('length',cell1);
for j = 1:r
i = 1;
while(i<c1(j))
if (cell1{j,1}(i).*(-1)) == (cell1{j,1}(i+1))
cell1{j,1}(i+1) = [];
cell1{j,1}(i) = [];
c1(j) = c1(j) - 2;
end
i = i + 1 ;
end
end
end
1 Comment
This actually provides the requested output:
C = {[-2,-1], [1,-2]; [1,-2], [2]; [1,-2,-1], [1,2]};
D = cellfun(@(c)[c{:}],num2cell(C,2),'UniformOutput',false);
fun = @(v)abs(diff(sign(v)))==2 & diff(abs(v))==0;
for k = 1:numel(D)
idx = fun(D{k});
while any(idx)
D{k} = D{k}([true,~idx]&[~idx,true]);
idx = fun(D{k});
end
end
and the output:
>> D{:}
ans =
-2 -2
ans =
1
ans =
1
EDIT if speed is important, then without cellfun will be faster:
C = {[-2,-1], [1,-2]; [1,-2], [2]; [1,-2,-1], [1,2]};
D = cell(size(C,1),1);
fun = @(v)abs(diff(sign(v)))==2 & diff(abs(v))==0;
for k = 1:numel(D)
D{k} = [C{k,:}];
idx = fun(D{k});
while any(idx)
D{k} = D{k}([true,~idx]&[~idx,true]);
idx = fun(D{k});
end
end
Categories
Find more on Matrix Indexing in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!