How do I edit certain cells of a cell-array with a logical index (without using for-loops)

8 views (last 30 days)
Hi everyone,
lets say I have a cell array and a numeric array like:
Old_Array = {20 , '2' ; 21 , '2' ; 22 , '2,3' ; 25 , '3' ; 28 , '2'};
and
new_Numbers = [18 ; 21 ; 22 ; 32];
What I want, is to some kind of mix those two. If a number of new_Numbers matches with the first column of old_Array, i want to add '4' to the cell in the 2nd column on just that row. If a number of new_Numbers is not matched, i want to add it, with the 2nd column containing the'4' String. The result should look like
New_Array = {18 , '4' ; 20 , '2' ; 21 , '2,4' ; 22 , '2,3,4' ; 25 , '3' ; 28 , '2' ; 32 , '4'};
I wonder if there is a solution not using for loops but [i,j]=ismember(new_Numbers,cell2mat(Old_Array(:,1))) and the logical indexes.
Thanks in advance. Any Help is appreciated! :)
  1 Comment
Mr Anderson
Mr Anderson on 12 Dec 2015
the for loop is indeed not that big, but perhaps anyone has a "logical-only" solution.
in the meantime if anyone else comes across this, this for-loop does the trick for me:
rs='4'
for n=1:length(new_Numbers)
[i,j] = ismember(new_Numbers(n),cell2mat(Old_Array(:,1)));
if i
Old_Array{j,2} = [Old_Array{j,2} ',' num2str(rs)];
else
pos_new_entry = length(Old_Array)+1;
Old_Array{pos_new_entry,1} = new_Numbers(n);
Old_Array{pos_new_entry,2} = num2str(rs);
end;
end;

Sign in to comment.

Accepted Answer

the cyclist
the cyclist on 12 Dec 2015
This is fairly inelegant, but it is a vectorized solution:
Old_Array = {20 , '2' ;
21 , '2' ;
22 , '2,3' ;
25 , '3' ;
28 , '2'};
new_Numbers = [18 ; 21 ; 22 ; 32];
% Find which numbers are really new
[tr,loc] = ismember(new_Numbers,cell2mat(Old_Array(:,1)));
% Initialize new array as a copy
New_Array = Old_Array;
% Append ',4' to rows that match
New_Array(loc(tr),2) = cellfun(@(x)[x,',4'],New_Array(loc(tr),2),'UniformOutput',false)
% Add new numbers that don't appear in old
Number_New_Numbers = sum(not(tr));
New_Block = [num2cell(new_Numbers(not(tr))),repmat({'4'},Number_New_Numbers,1)]
New_Array = [New_Array; New_Block]
% Sort the new array
[~,sortingIndex] = sort([New_Array{:,1}]')
New_Array = New_Array(sortingIndex,:)
  3 Comments
the cyclist
the cyclist on 12 Dec 2015
I think you have it basically correct, but I would explain it like this.
@(x)[x,',4'] should be considered as one functional unit. It is the definition of an anonymous function.
I could have defined it separately, like this:
append_4_func = @(x)[x,',4'];
New_Array(loc(tr),2) = cellfun(append_4_func,New_Array(loc(tr),2),'UniformOutput',false)
What cellfun does, in general, is apply a function to each element of the input cell array, and output the result. In this particular case, that function is "append ',4' to a string".
Then, as you say, then output of cellfun is assigned back into New_Array again.
Finally, I would just mention that I have some doubts that this will be faster than a for loop. You might want to do some testing. The vectorized code is pretty obscure, and future-you might find it confusing.
The best form of "thanks" is upvoting and/or accepting a solution that you found useful. That rewards the contributor, and may point future users to helpful solutions.
Mr Anderson
Mr Anderson on 12 Dec 2015
Those anonymous functions have been a mistery to me since beginning with matlab and cell-arrays. Now thanks to your help I kinda found out how they work, and even though I might use the for loop on this task, I already can use the new knowledge for other parts of my work.
Again, thank you so much and have great christmas holidays! :)

Sign in to comment.

More Answers (0)

Categories

Find more on Characters and Strings in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!