Fill cell array with elements based on the indices MATLAB

匿名 (未验证) 提交于 2019-12-03 03:04:01

问题:

I have a n*m cell array Cell_In:

a b * * * * c * * d * * * f 

* --> represents empty string (''). Here is what I need:

a b a b a b c b c d c d c f 

For a particular column I need to fill the empty cell with the previous non-empty cell until another non-empty cell is found. Following is the code what I wrote.

b = ~cellfun(@isempty,a); c = [find(b(:,1) == 1);size(a,1)+1]; e = diff(c); d = [find(b(:,2) == 1);size(a,1)+1]; f = diff(d); s1 = ''; s2 = ''; for i = 1:length(e)     s1 = [s1,repmat(a(c(i),1),1,e(i))]; end  for i = 1:length(f)     s2 = [s2,repmat(a(d(i),2),1,f(i))]; end Cell_Out = [s1',s2']; 

It's working fine but I want to know the best solution?

回答1:

Assuming A to be the input cell array, there could be two approaches here.

Approach #1

%// Initlialize output array Aout = cell(size(A));  for k = 1:size(A,2)      %// Select one column     Ak = A(:,k);      %// Logical array with size of Ak and ones at places with non-empty strings     pos = cellfun(@(x) ~isempty(x), Ak);      %// Find unique strings and find indices for all places in that column     %// with respect to those unique strings     [unq_str,~,str_idx] = unique(Ak,'stable');      %// Perform cumsum on pos to get an array with a "stepped" array that     %// steps up at each non-empty string position.     %// Then replace each stepping number with the string IDs     idx = changem(cumsum(pos),str_idx(pos),1:sum(pos));      %// Index into each column with those replaced IDs for the final output     Aout(:,k) = unq_str(idx); end 

With the input slightly changed for testing out the solution code a bit more aggressively, we had after code run -

A =      'a'    'b'     ''     ''      ''     'a'     'c'    ''      ''     'd'     'a'    ''      ''     'f'     'c'    'a'  Aout =      'a'    'b'     'a'    'b'     'a'    'a'     'c'    'a'     'c'    'd'     'a'    'd'     'a'    'f'     'c'    'a' 

Approach #2 [Compact and maybe more efficient]

You can reshape the input cell array into a single columned cell array and as such you won't need to loop through the columns of the cell array and this could lead to a more efficient and compact code -

%// Reshape all cells into a single columned cell array A1 = A(:);  %// Rest of the code borrowed from previous approach with reshaping added %// at the end to bring the output back to the size of input array pos = ~cellfun('isempty', A1); [unq_str,~,str_idx] = unique(A1,'stable'); Aout =  reshape(unq_str(changem(cumsum(pos),str_idx(pos),1:sum(pos))),size(A)); 

Bonus: Customized implementation of changem

The codes listed earlier uses changem that needs Mapping Toolbox. So, if you do have it, here's a customized version of it, implemented with bsxfun and max and is merely a polished version of an earlier solution code posted here. Here goes the custom function code -

%// CHANGEM_CUSTOM  Home-cooked vesion of CHANGEM with MAX, BSXFUN function A  = changem_custom(A,newvals,oldvals)  [valid,id] = max(bsxfun(@eq,A(:),oldvals(:).'),[],2); %//' A(valid) = newvals(id(valid));  return; 

So, to use this custom function to replace changem, just replace the function call name there in the earlier codes.



回答2:

This solution gets the indices of empty cells and fills it with the data from the previous one. To fill larger gaps multiple steps are required.

ix=find(cellfun(@isempty,M)) while numel(ix)>0, M(ix)=M(ix-1);ix=find(cellfun(@isempty,M)); end 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!