Sorting a cell array - matlab

I want to sort the rows according to their second entries, i.e. by second column. Each entry of the second column is an array chars(representing a time stamp). There also might be missing values, i.e. the entry in the second column can be []. How do I do this?

you need to use the sortrows() function
if the matrix you wanted to sort is A then use
sorted_matrix = sortrows(A,2);
http://www.mathworks.com/help/techdoc/ref/sortrows.html

I would first convert the time stamps from strings to numeric values using the function DATENUM. Then you will want to replace the contents of the empty cells with a place holder, like NaN. The you can use the function SORTROWS to sort based on the second column. Here is an example:
>> mat = {1 '1/1/10' 3; 4 [] 6; 7 '1/1/09' 9} %# Sample cell array
mat =
[1] '1/1/10' [3]
[4] [] [6]
[7] '1/1/09' [9]
>> validIndex = ~cellfun('isempty',mat(:,2)); %# Find non-empty indices
>> mat(validIndex,2) = num2cell(datenum(mat(validIndex,2))); %# Convert dates
>> mat(~validIndex,2) = {NaN}; %# Replace empty cells with NaN
>> mat = sortrows(mat,2) %# Sort based on the second column
mat =
[7] [733774] [9]
[1] [734139] [3]
[4] [ NaN] [6]
The NaN values will be sorted to the bottom in this case.

Related

Apply cellfun to only one column in cell array

I know cellfun can be applied to an entire cell array and understand its syntax. However is it possible to apply cellfun only to one column in a cell array and not have it affect the other columns?
As user1543042 and It's magic said in the comments, you can apply the cell function to just one column using ':', but you want to add an assignment step. Also, as you want the cell function to return a cell array, you need to flag non-uniformoutput. So, you end up with:
C(:,i) = cellfun(#foo, C(:,i), 'UniformOutput', false)
To see an example in action:
>> C = {1,2,3;4 5 6};
>> C
C =
[1] [2] [3]
[4] [5] [6]
>> size(C)
ans =
2 3
>> cellfun(#(x)x.^2,C(:,1))
ans =
1
16
>> C(:,1) = cellfun(#(x)x.^2,C(:,1))
Conversion to cell from double is not possible.
>> C(:,1) = cellfun(#(x)x.^2,C(:,1),'UniformOutput',false)
C =
[ 1] [2] [3]
[16] [5] [6]
>>

Merging elements of different cells

Suppose, we have a cell array consisting of ids and one attribute, e.g.
A{1,1}=[1 2;2 4]
A{1,2}=[2 3 5;8 5 6]
Now, I'd like to have a final output consisting of unique ids of two cells (first row values) and corresponding columns have attribute value of each cell separately.
i.e.
C =
[1] [ 2]
[2] [1x2 double] % 4 in first cell and 8 in second cell
[3] [ 5]
[5] [ 6]
it seems that it's not possible to use something like C=[unique(A{1,:}(1,:)')]. Any help is greatly appreciated.
Assuming that each cell has two rows and a variable amount of columns where the first row is the ID and the second row is an attribute, I'd consolidate all of the cells into a single 2D matrix and use accumarray. accumarray is very suitable here because you want to group values that belong to the same ID together and apply a function to it. In our case, our function will simply place the values in a cell array and we'll make sure that the values are sorted because the values that are grouped by accumarray per ID come into the function in random order.
Use cell2mat to convert the cells into a 2D matrix, transpose it so that it's compatible for accumarray, and use it. One thing I'll need to note is that should any IDs be missing, accumarray will make this slot empty. What I meant by missing is that in your example, the ID 4 is missing as there is a gap between 3 and 5 and also the ID 6 between 5 and 7 (I added the example in your comment to me). Because the largest ID in your data is 7, accumarray works by assigning outputs from ID 1 up to ID 7 in increments of 1. The last thing we would need to tackle is to eliminate any empty cells from the output of accumarray to complete the grouping.
BTW, I'm going to assume that your cell array consists of a single row of cells like your example.... so:
%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];
%// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
B = cell2mat(A).';
%// Group IDs together and ensure they're sorted
out = accumarray(B(:,1), B(:,2), [], #(x) {sort(x)});
%// Add a column of IDs and concatenate with the previous output
IDs = num2cell((1:numel(out)).');
out = [IDs out];
%// Any cells from the grouping that are empty, eliminate
ind = cellfun(#isempty, out(:,2));
out(ind,:) = [];
We get:
out =
[1] [ 2]
[2] [2x1 double]
[3] [ 5]
[5] [ 6]
[7] [ 8]
>> celldisp(out(2,:))
ans{1} =
2
ans{2} =
4
8
If you'd like this done on a 2D cell array, where each row of this cell array represents a separate instance of the same problem, one suggestion I have is to perhaps loop over each row. Something like this, given your example in the comments:
%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];
A{2,1}=[1 2;2 4];
A{2,2}=[1;7];
%// Make a cell array that will contain the output per row
out = cell(size(A,1),1);
for idx = 1 : size(A,1)
%// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
B = cell2mat(A(idx,:)).';
%// Group IDs together and ensure they're sorted
out{idx} = accumarray(B(:,1), B(:,2), [], #(x) {sort(x)});
%// Add a column of IDs and concatenate with the previous output
IDs = num2cell((1:numel(out{idx})).');
out{idx} = [IDs out{idx}];
%// Any cells from the grouping that are empty, eliminate
ind = cellfun(#isempty, out{idx}(:,2));
out{idx}(ind,:) = [];
end
We get:
>> out{1}
ans =
[1] [ 2]
[2] [2x1 double]
[3] [ 5]
[5] [ 6]
[7] [ 8]
>> out{2}
ans =
[1] [2x1 double]
[2] [ 4]
>> celldisp(out{1}(2,:))
ans{1} =
2
ans{2} =
4
8
>> celldisp(out{2}(1,:))
ans{1} =
1
ans{2} =
2
7

In Matlab, How to eliminate empty columns from the cell array?

So in 3 X 18 cell array, 7 columns are empty and I need a new cell array that's 3 X 11. Any suggestions without going for looping ?
Let's consider the following cell array. Its second column consists only of [], so it should be removed.
>> c = {1 , [], 'a'; 2, [], []; 3, [], 'bc'}
c =
[1] [] 'a'
[2] [] []
[3] [] 'bc'
You can compute a logical index to tell which columns should be kept and then use it to obtain the result:
>> keep = any(~cellfun('isempty',c), 1); %// keep columns that don't only contain []
keep =
1 0 1 %// column 2 should be removed
>> result = c(:,keep)
result =
[1] 'a'
[2] []
[3] 'bc'
How it works:
cellfun('isempty' ,c) is a matrix the same size as c. It contains 1 at entry (m,n) if and only if c{m,n} is empty.
~cellfun('isempty' ,c) is the logical negation of the above, so it contains 1 where c is not empty.
any(~cellfun('isempty' ,c), 1) applies any to each column of the above. So it's a row vector such that its m-th entry equals 1 if any of the cells of c in that column are non-empty, and 0 otherwise.
The above is used as a logical index to select the desired columns of c.
Use cellfun to detect elements, then from that find columns with empty elements and delete those:
cellarray(:, any(cellfun(#isempty, cellarray), 1)) = [];
If instead you'd like to keep columns with at least one non-empty element, use all instead of any.
For example:
>> cellarray = {1 2 ,[], 4;[], 5, [], 3}
[1] [2] [] [4]
[] [5] [] [3]
>> cellarray(:,any(cellfun(#isempty, cellarray), 1))=[]
cellarray =
[2] [4]
[5] [3]

How to remove an alphabet from a list of numbers in Matlab?

I have a list of numbers in a column vector. In those numbers i have an alphabet M which appears at random intervals..
this link How to delete zero components in a vector in Matlab?
display how to remove the Zero, i tried to adapt how to remove M, but in vain.!
How do I replace this M by 0?
I tried this code but to no avail.!
I called all my sample data N.
N=[4.6
6.7
4.1
3.1
M
2.6]
N(N==M) = [];
i also tried this code
sample=N(N~=M);
My real data is loaded from a text file:
filename='x.txt';
N=importdata(filename)
The problem is that your M items are never being imported by importdata in the first place!
importdata is the wrong function to use for complex data. If you put this in x.txt:
4.6
6.7
4.1
3.1
M
2.6
Then the output of N=importdata(filename) is simply the first four values. It can't handle the M. You should notice this, because the size of N should be smaller than the number of values in your file.
Instead, use textscan, telling it that M is an invalid item and should be replaced with 0:
fid = fopen('x.text');
N = textscan(fid,'%f','treatAsEmpty',{'M'},'EmptyValue',0);
fclose(fid);
N{1}
ans =
4.6000
6.7000
4.1000
3.1000
0
2.6000
Additional note: it's probably a bad idea to put 0 in where you mean this value was bad, because it will affect the results you get from other functions. I would set EmptyValue to NaN instead.
Assumes that you do not really have numbers, but numbers as a string. This means that you can use the function strrep.
try:
A = ['1 2 3 4 M 6'];
strrep(A,'M', '0');
Hey unfortunately you haven't provided what kind of datatype you have in N. As given by OP double doesn't make sense, because M is not a valid double value as far as I know.
So I assume that you have a cell array containing doubles or strings placed in cells. If so this code works:
N={ 1 2 2 42 5 12 'M' 'm' 123}
alphabet=['A':'Z','a':'z'];
for k=1:numel(N)
if ismember(N{k},alphabet)
N{k}=0;
end
end
display(N)
resulting in following console output:
input
N =
[1] [2] [2] [42] [5] [12] 'M' 'm' [123]
output
N =
[1] [2] [2] [42] [5] [12] [0] [0] [123]
You can change what the replacement is in the if statement.
The code can be modified to fit a string as input:
N=['1 2 2 42 5 12 M m 123']
alphabet=['A':'Z','a':'z'];
for k=1:numel(N)
if ismember(N(k),alphabet)
N(k)='0';
end
end
display(N)

Searching a cell array of vectors and returning indices

I have a 3000x1 cell array of vectors of different lengths and am looking for a way to search them all for a number and return the cell indices for the first and last occurrence of that number.
So my data looks like this:
[1]
[1 2]
[1 2]
[3]
[6 7 8 9]
etc
And I want to my results to look like this when I search for the number 1:
ans = 1 3
All the indices (e.g. [1 2 3] for 1) would also work, though the above would be better. So far I'm unable to solve either problem.
I've tried
cellfun(#(x) x==1, positions, 'UniformOutput', 0)
This returns a logical array, effectively putting me back at square 1. I've tried using find(cellfun...) but this gives the error undefined function 'find' for input arguments of type 'cell'. Most of the help I can find is for searching for strings within a cell array. Do I need to convert all my vectors to strings for this to work?
C = {[1]
[1 2]
[1 2]
[3]
[6 7 8 9]}; %// example data
N = 1; %// sought number
ind = cellfun(#(v) any(v==N), C); %// gives 1 for cells which contain N
first = find(ind,1);
last = find(ind,1,'last');
result = [ first last ];