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

3 次查看(过去 30 天)
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 个评论
Mr Anderson
Mr Anderson 2015-12-12
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;

请先登录,再进行评论。

采纳的回答

the cyclist
the cyclist 2015-12-12
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 个评论
the cyclist
the cyclist 2015-12-12
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 2015-12-12
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! :)

请先登录,再进行评论。

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Characters and Strings 的更多信息

Community Treasure Hunt

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

Start Hunting!

Translated by