1
votes

I have a cell array consisting of numbers, strings, and empty arrays. I want to find the position (linear or indexed) of all cells containing a string in which a certain substring of interest appears.

mixedCellArray = {
   'adpo' 2134  []
   0 [] 'daesad'
   'xxxxx' 'dp' 'dpdpd'
}

If the substring of interest is 'dp', then I should get the indices for three cells.

The only solutions I can find work when the cell array contains only strings:

One work-around is to find all cells not containing strings, and fill them with '', as hinted by this posting. Unfortunately, my approach requires a variation of that solution, probably something like cellfun('ischar',mixedCellArray). This causes the error:

Error using cellfun
Unknown option. 

Thanks for any suggestions on how to figure out the error.

I've posted this to usenet

EDUCATIONAL AFTERNOTE: For those who don't have Matlab at home, and end up bouncing back and forth between Matlab and Octave. I asked above why cellfun doesn't accept 'ischar' as its first argument. The answer turns out to be that the argument must be a function handle in Matlab, so you really need to pass @ischar. There are some functions whose names can be passed as strings, for backward compatibility, but ischar is not one of them.

4
See: timing results. Note the performance disadvantage of tweet-style one line coding.excaza

4 Answers

4
votes

How about this one-liner:

>> mixedCellArray = {'adpo' 2134  []; 0 [] 'daesad'; 'xxxxx' 'dp' 'dpdpd'};
>> index = cellfun(@(c) ischar(c) && ~isempty(strfind(c, 'dp')), mixedCellArray)

index =

  3×3 logical array

   1   0   0
   0   0   0
   0   1   1

You could get by without the ischar(c) && ..., but you will likely want to keep it there since strfind will implicitly convert any numeric values/arrays into their equivalent ASCII characters to do the comparison. That means you could get false positives, as in this example:

>> C = {65, 'A'; 'BAD' [66 65 68]}  % Note there's a vector in there

C =

  2×2 cell array

    [ 65]    'A'         
    'BAD'    [1×3 double]

>> index = cellfun(@(c) ~isempty(strfind(c, 'A')), C)  % Removed ischar(c) &&

index =

  2×2 logical array

   1   1                % They all match!
   1   1
4
votes

Just use a loop, testing with ischar and contains (added in R2016b). The various *funs are basically loops and, in general, do not offer any performance advantage over the explicit loop.

mixedCellArray = {'adpo' 2134  []; 0 [] 'daesad'; 'xxxxx' 'dp' 'dpdpd'};
querystr = 'dp';

test = false(size(mixedCellArray));
for ii = 1:numel(mixedCellArray)
    if ischar(mixedCellArray{ii})
        test(ii) = contains(mixedCellArray{ii}, querystr);
    end
end

Which returns:

test =

  3×3 logical array

   1   0   0
   0   0   0
   0   1   1

Edit:

If you don't have a MATLAB version with contains you can substitute a regex:

test(ii) = ~isempty(regexp(mixedCellArray{ii}, querystr, 'once'));
2
votes
z=cellfun(@(x)strfind(x,'dp'),mixedCellArray,'un',0);
idx=cellfun(@(x)x>0,z,'un',0);
find(~cellfun(@isempty,idx))
0
votes

Here is a solution from the usenet link in my original post:

>> mixedCellArray = {
         'adpo' 2134  []
         0 [] 'daesad'
         'xxxxx' 'dp' 'dpdpd'
      }

mixedCellArray =
    'adpo'     [2134]          []
    [    0]        []    'daesad'
    'xxxxx'    'dp'      'dpdpd'

>> ~cellfun( @isempty , ...
             cellfun( @(x)strfind(x,'dp') , ...
                      mixedCellArray , ...
                      'uniform',0) ...
           )

ans =
     1     0     0
     0     0     0
     0     1     1

The inner cellfun is able to apply strfind to even numerical cells because, I presume, Matlab treats numerical arrays and strings the same way. A string is just an array of numbers representing the character codes. The outer cellfun identifies all cells for which the inner cellfun found a match, and the prefix tilde turns that into all cells for which there was NO match.

Thanks to dpb.