Copy array by indexing cell numbers - matlab

I am trying to extract specific columns from a "nested" array, the columns I need are nested, there are about a thousand columns, of which I only need the ones marked by index in another part of the array.
I have one Array{1,15} containing cells with numerical values (e.g. 2,5,10,53). These values are the index numbers i need to extract from another array.
indexnum = OutArray{1,15}(:);
Which arranges them in a column instead of a row, totally not necessary but seemed easier for me to progress with this.
Then I have the array containing the actual columns I want to extract/copy to a new array.
OutArray{1,14}{i,1}
So by the example numbers above, I need to copy column 2,5,10 and 53 to another array.
One of my more current attempts looks like this:
NewArray = []; %create new array
indexnum = OutArray{1,15}(:); %copy right index values to column
for i = indexnum{:} %use numeric value of every cell
NewArray = [NewArray, OutArray{1,14}{1,i}] %copy corresponding columns to NewArray
end
I also tried to use cell2mat(indexnum(1,:)), but that didn't help either.
To make clear the structure of the array:
OutArray{1,15} Contains cells with 1 value per column, which are index numbers for other array
OutArray{1,14} contains nested cells, 1 cell per column
OutArray{1,14}{1,x} contains columns with ~30 values per column, of which I want to copy the columns with the right indexes
For another array in which I just needed to copy all columns this code worked fine:
new1 = [];
for i = 1:length(OutArray{1,4})
new1 = [new1, OutArray{1,4}{i,1}]
end

It was a bit hard to understand because of so many cells into cells but your screenshots were very helpful. I will first highlight the errors and needed changes in your attemp:
NewArray = []; %create new array
indexnum = OutArray{1,15}(:); %copy right index values to column
for i = indexnum{:} %use numeric value of every cell
NewArray = [NewArray, OutArray{1,14}{1,i}] %copy corresponding columns to NewArray
end
Doing OutArray{1,15}(:) is exactly the same as OutArray{1,15} as you are just selecting the full cell of cells.
Your for loop uses indexnum{:} as the iterator but {:} returns a comma separated list and it does not work like (:) for arrays that give the full vector instead. In this case, when you assign indexnum{:} to a variable you get only the first element of the list. An example to ilustrate this:C = {1, 2, 3}; C{:} displays the full list, but x = C{:} only makes x = 1. To get all the elements you could group them in an array by doing: x = [C{:}].
So in your case you just need to add brackets to for i = [indexnum{:}] to get the iterator working.
To sum up, your code would be changed to:
NewArray = []; %create new array
indexnum = OutArray{1,15}; %copy right index values to column
for i = [indexnum{:}]
NewArray = [NewArray, OutArray{1,14}{1,i}}];
end
In addition, you could avoid the for loop and variables initialization with this single line code:
NewArray = [OutArray{1,14}{1,[OutArray{1,15}{1,:}]}];
As you can see, it just takes row 1 of your data OutArray{1,14} and the columns specified at each element of the indexes OutArray{1,15}. Brackets are needed twice because when indexing a cell with curly braces with more than one index at a time you always get a list and need to convert into an array as explained above.

Related

Convert cell array columns into matrix columns

I have a cell array (16x5) and I would like to extract all the values held in each column of the cell array and place them into a column within a matrix such that the columns are preserved (i.e. new matrix column for each cell array column).
What is the best way to do this?
I have tried:
for k=1:Samples
data(k,:) = [dist{:,k}];
end
But this returns the error
Subscripted assignment dimension mismatch.
However I am not sure why.
EDIT - Cell array structure:
Since your loop code is valid, I assume the error is being raised because data is preallocated with dimensions not matching the length of the comma-expanded dist column (Matlab will grow matrices with explicit indices but not with the : operator).
You just need to get the length of the data after the comma-separated expansion:
nElem = numel([dist{:,1}]);
Samples = size(dist,2);
data = zeros(Samples,nElem);
for k=1:Samples
data(k,:) = [dist{:,k}];
end
Or if you want it in columns
data = zeros(nElem,Samples);
for k=1:Samples
data(:,k) = [dist{:,k}]';
end

Adding 0's to cell array such that each column contains an equal number of entries - MATLAB

I have a 16x100 (varies in size) cell array and I would like to extract each of it's columns into a column of a matrix. When each column of the cell array contains an identical number of entries I can use:
elem = numel([dist{:,1}]);
repeat = size(dist,2);
data = zeros(elem,repeat);
for k=1:repeat
results(:,k) = [dist{:,k}]';
end
However there are some instances where there are not an equal number thus it returns the error:
Subscripted assignment dimension mismatch.
What is the best way around this? Is there a way to add zeroes to equalise the number of entries?
Perfect setup for bsxfun's masking capability here!
Now, I am assuming your data is setup as described in your previous question -
To solve the case of filling up "empty spaces" with zeros, you can setup an output array with maximum possible number of elements in each column and then fillup the valid spaces with the values from the input cell array, with the valid spaces being detected by the logical mask created with bsxfun. Read on through the comments inlined within the code listed next to find out the exact ideas on solving it -
%// Get the number of elements in each column of the input cell array
lens = sum(cellfun('length',a),1)
%// Store the maximum number of elements possible in any column of output array
max_lens = max(lens)
%// Setup output array, with no. of rows as max number of elements in each column
%// and no. of columns would be same as the no. of columns in input cell array
results = zeros(max_lens,numel(lens))
%// Create as mask that has ones to the "extent" of number of elements in
%// each column of the input cell array using the lengths
mask = bsxfun(#le,[1:max_lens]',lens) %//'
%// Finally, store the values from input cell array into masked positions
results(mask) = [a{:}]

subindex into a cell array of strings

I have a 6 x 3 cell (called strat) where the first two columns contain text, the last column has either 1 or 2.
I want to take a subset of this cell array. Basically select only the rows where the last column has a 1 in it.
I tried the following,
ff = strat(strat(:, 3), 1:2) == 1;
The error message is,
Function 'subsindex' is not defined for values of class 'cell'.
How can I index into a cell array?
Cell arrays are accessed through braces {} instead of parentheses (). Then, as a 2nd subtlety, when pulling values out of a cell arrays, you need to gather them...for numerics you gather them into regular arrays using [] and for strings you gather them into a new cell array using {}. Confusing, eh?
ff = { strat{ [strat{:,3}]==1 , 1:2 } };
Gathering into cell arrays this way can often give the wrong shape when you're done. So, you might try something like this
ind = find([strat{:,3}]==1); %find the relevant indices
ff = {{strat{ind,1}; strat{ind,2}}'; %this will probably give you the right shape

find top n numeric cells in a cell array

Hi I have a cell array 2 x 1000. the first column holds numeric (double) values, the second holds a string. i would like the find all cells in the first column that are above a certain value, and bring back the corresponding cells in the second column. I have tried strcamp and various others but obviously they are for strings. I also tried doing
sortrows(mycell(1,:));
so i could pick the first 50 rows off or whateever, but this didn't seem to order the cell array. but really i would like to specifiy a threshold on the first column of the cell array.
How do I do this?
thanks.
If C is your cell array:
nums = [C{:,1}];
{:} converts C into a comma separated list (so {:,1} only converts the first column) and then [] collects the results into a normal array. After that it's simple:
index = nums > Threshold;
C(index,:)
OR in a one liner:
C([C{:,1}] > Threshold, :) %// Or C([C{:,1}] > Threshold, 2) as Luis said

regarding saving the numerical and string values altogether

I have a string matrix with N rows and 2 columns. Each cell stores a string. I have another N*1 vector, where each entry is a numerical value.
How can I save these two structures into a single text file row by row.
In other words, each row of the saved text file is composed of three elements, the first two elements come from a row of the string matrix and the third element comes from the corresponding row of that vector.
Thanks.
If I understand correctly, then fake data can be represented as this:
% Both have N=2 rows
strMat1 = {'a','b';'c','d';};
strMat2 = {1;2};
And if you want the output of this data to be a text file with:
ac1
bd2
Then you should do this:
txtOut = [];
if size(strMat1,1) == size(strMat2,1);
for row = 1:size(strMat1,1)
txtOut= [txtOut strMat1{:,row} num2str(strMat2{row}) '\n'];
end
else
disp('Size disagreement')
end
fid=fopen('textData.txt','wt');
fprintf(fid,txtOut)
It checks the vectors to make sure there are the same number of rows and then creates a txtOut string to be passed to a fprintf command.
Hope this helps! If you wanted the output to be spaced differently, just add spaces to the appending line in the form of ' ' .