Reputation: 709
I have a 4x1 cell array containing string identifiers, and a 4x5 cell array containing 5 data points for each of these entities over time...
>> ids = { '1'; '2'; 'A'; '4' }
ids =
'1'
'2'
'A'
'4'
>> vals = { 11, 12, 13, 14, 15; 21, 22, 23, 24, 25; 31, 32, 33, 34, 35;, 41, 42, 43, 44, 45}
vals =
[11] [12] [13] [14] [15]
[21] [22] [23] [24] [25]
[31] [32] [33] [34] [35]
[41] [42] [43] [44] [45]
I want to convert IDs to numbers and strip out data in both cell arrays for non-numeric IDs, leaving:
ids =
[1]
[2]
[4]
vals =
[11] [12] [13] [14] [15]
[21] [22] [23] [24] [25]
[41] [42] [43] [44] [45]
I am wondering if the key to this is working out which indexes are empty and then addressing both cell arrays with these indexes, but I'm not sure where to go after this...
>> numericIds = cellfun(@str2num, ids, 'un', 0)
numericIds =
[1]
[2]
[]
[4]
>> emptyIdx = cellfun(@isempty, numericIds, 'un', 0)
emptyIdx =
[0]
[0]
[1]
[0]
>> ids(emptyIdx) = []
Error using subsindex
Function 'subsindex' is not defined for values of class 'cell'.
Upvotes: 1
Views: 4331
Reputation: 65460
As others have said, the root of your problem is that you're trying to use a cell array as an index. This is because the uniform
input to cellfun
determines whether to return a numeric array (true
) of cell array (false
).
That being said, I would probably not use cellfun
and would probably just use str2double
directly on the cell array to figure out which ones are valid numbers (it returns a NaN for non-numbers).
ids = str2double(ids);
tokeep = ~isnan(ids);
ids = ids(tokeep);
vals = vals(tokeep, :)
NOTE: In general, most functions that operate on strings (such as
str2double
) also operate on cell arrays of strings.
Upvotes: 2
Reputation: 104535
For the second call to cellfun
with emptyIdx
, don't specify the UniformOutput
flag to be 0. Remove that option and it will create a logical vector that you can use to index into your cell array directly and you can remove entries.
As such, you would do this instead:
emptyIdx = cellfun(@isempty, numericIds);
Once you do this, you can use logical indexing to remove the affected rows:
ids(emptyIdx) = [];
vals(emptyIdx,:) = [];
Here's a running example:
>> ids = { '1'; '2'; 'A'; '4' }
ids =
'1'
'2'
'A'
'4'
>> numericIds = cellfun(@str2num, ids, 'un', 0)
numericIds =
[1]
[2]
[]
[4]
>> emptyIdx = cellfun(@isempty, numericIds)
emptyIdx =
0
0
1
0
>> vals = { 11, 12, 13, 14, 15; 21, 22, 23, 24, 25; 31, 32, 33, 34, 35;, 41, 42, 43, 44, 45}
vals =
[11] [12] [13] [14] [15]
[21] [22] [23] [24] [25]
[31] [32] [33] [34] [35]
[41] [42] [43] [44] [45]
>> vals(emptyIdx,:) = []
vals =
[11] [12] [13] [14] [15]
[21] [22] [23] [24] [25]
[41] [42] [43] [44] [45]
>> ids(emptyIdx) = []
ids =
'1'
'2'
'4'
Upvotes: 2