MATLAB: How to access and edit a cell array using a double for indexes

cellcell arraycell arraysfor loopindexingloopsMATLABvectorization

Hi everyone,
working on some data, I came across a topic I avoided since starting with Matlab half a year ago. It's about indexing, accessing and editing data in a cell array. For example I got a 300000×1 cell array 'results' filled with 50 city names stored in a 50×1 cell named 'cities'. So each cell of 'results' contains one of the 50 names. What I want to do, is replacing the names in 'results' with their position/index in 'cities', in order to turn it into a double array and to save computing time for following tasks. I tried the following.
for k=1:length(cities)
cells = find(ismember(results,cities(k,1)));
results(cells) = k;
end;
Wich just produces the error Conversion to cell from double is not possible. I tried this because cells contains the indexes in 'results' of the just called city (cities(k,1)) And i thought this way I could also edit the values, which is obviously not possible.
My workaround would be the combination of 2 for loops, which is, regarding the length of the 'results' arrays, pretty slow.
for k=1:length(cities)
cells = find(ismember(results,cities(k,1)));
for n=1:length(cells)
results{cells(n,1),1} = num2str(k); %num2str because otherwise k-loop would not work for k>=2
end;
end;
% cellfun(@str2num, results(:,1)) in the end to convert the strings to num
But how do I get the first solution to work? How to I access the cell array correctly with a double as indexing? And is the first way really faster than the 'loop-Way'?
Many thanks in advance!
Best regards!

Best Answer

Note that you cannot "turn it into a double array": you can only reassign variable names to a new variable, but this would completely replace the old cell array.
The basic problem with your first loop is there is some confusion about cell array indexing: you try to allocate a double to a cell, thus the error. If you had put the double inside the cell then it would have worked:
for k = 1:numel(cities)
idx = ismember(results,cities(k,1));
results{idx} = k;
end
Cell array indexing in a nutshell:
  • parentheses () refer to the cells themselves.
  • curly braces {} refer to the contents of the cells.
So given that results is a cell array, and k is a double, your line results(cells) = k tries to allocate the double to the cell itself, whereas what you needed to do was allocate it to the contents of the cell using curly braces: results{cells} = k.
Easiest Solution
The easiest solution is to use the second output from ismember:
>> cities = {'london','berlin','paris'};
>> results = {'berlin','paris','paris','london','paris','london','berlin','london'};
>> [~,LocB] = ismember(results,cities)
LocB =
2 3 3 1 3 1 2 1
Alternative Solution
If your really want to do this in a loop:
>> out = nan(1,numel(results));
>> for k = 1:numel(cities), out(strcmp(results,cities{k})) = k; end
>> out
out =
2 3 3 1 3 1 2 1
Note that we loop over the smaller cell array cities, not the larger one results, and we use logical indexing rather than using slow find.