I would like to sort a cell array according to one of the columns. The array is created by textscan function. There are some answers on web, but I still cannot get it working. I have the following array:
>> DATA
DATA =
{303427x1 cell} {303427x1 cell} {303427x1 cell} {303427x1 cell} [303427x1 uint32] [303427x1 double] [303427x1 uint32] [303427x1 int32] {303427x1 cell}
Important is the sixth column, which are times converted by datenum function. I want to sort the whole DATA by this column but with the link to another columns.
Normal sort or sortrows doesnt work for me. Could you help me please?
I take it you want to sort within each cell of DATA, correct? The datenum function produces serial time stamps since "year zero," so they can be sorted normally.
times = DATA{6};
[~,idx] = sort(times,'ascend');
for i=1:length(DATA)
DATA{i} = DATA{i}(idx);
end
You can avoid for-loop in #reve_etrange's answer by using CELLFUN after you get the sorting index idx.
DATA = cellfun(#(x) x(idx), DATA, 'UniformOutput', false);
Related
I'm trying to make some logic work with some legacy matlab code. I figured the easist thing was to make the data look the same as what the code is expecting.
I'm reading the relevant data from a CSV file, it's pretty simple -- but the format for the IDs changed from a simple number to an ID of the form [YY,ZZZZ].
As an example, the 'previous' CSV data looked like:
1,Simple,Data
2,More,Data-Dash-Data
3,Even,More
4,Really,More
The 'new' CSV data looks like:
[01,0001],Simple,Data
[02,1001],More,Data-Dash-Data
[03,9876],Even,More
[04,1234],Really,More
Previously, to read in the data, this logic was used:
fid = fopen(fileName);
data = textscan(fid,'%s%s%s%*s','Delimiter',',');
When this was done against the 'previous' CSV data, it returned data that look like this:
data =
1×3 cell array
{4×1 cell} {4×1 cell} {4×1 cell}
The cells then look like:
K>> data{:}
ans =
4×1 cell array
'1'
'2'
'3'
'4'
ans =
4×1 cell array
'Simple'
'More'
'Even'
'Data'
ans =
4×1 cell array
'Data'
'Data-Dash-Data'
'More'
'Data'
So to handle the ID of the form [YY,ZZZZ], I had to modify the 'textscan' logic to handle the new ID format that we're using. To do that, I'm using a regexp function:
fid = fopen(fileName);
rawData = textscan(fid,'%s','Delimiter','\n');
data = regexp(rawData{1},'[ \-\/\w]*([\[][^\)\]]*[\]])?', 'match')
This then, after it reads in the data, gives me data that is formatted like this:
K>> data
data =
4×1 cell array
{1×3 cell}
{1×3 cell}
{1×3 cell}
{1×3 cell}
K>> data{:}
ans =
1×3 cell array
'[01,0001]' 'Simple' 'Data'
ans =
1×3 cell array
'[02,1001]' 'More' 'Data-Dash-Data'
ans =
1×3 cell array
'[03,9876]' 'Even' 'More'
ans =
1×3 cell array
'[04,1234]' 'Really' 'More'
So you can see that it has the correct data in it -- but the data is laid out differently which is breaking on the legacy code. So my question is how can I make the 'new' data be laid out like this as it was coming out of the 'textscan' logic:
data =
1×3 cell array
{4×1 cell} {4×1 cell} {4×1 cell}
You can use fileread to read in the raw file directly. Afterwards, you can use a regex which splits on either a comma, not followed by a digit, or on a carriage return.
c = regexp(fileread(fileName),',(?!\d)|\r\n','split');
formattedData = {c(1:3:end)',c(2:3:end)',c(3:3:end)'};
>> formattedData
formattedData =
1×3 cell array
{4×1 cell} {4×1 cell} {4×1 cell}
I want to import some data in an m file. So for I have managed to create a cell array of the data. I want to convert it into a matrix. I used cell2mat but I get an error. I'm new to Matlab, so I would like some help. Here is my complete code
fid = fopen('vessel-movements.csv');
C = textscan(fid, '%f %f %f %f %f %s %s %s', 'HeaderLines', 1, 'Delimiter', ',')
fclose(fid);
iscell(C)
T = cell2mat(C)
The answer I get is:
C =
Columns 1 through 4
[300744x1 double] [300744x1 double] [300744x1 double] [300744x1 double]
Columns 5 through 8
[300744x1 double] {300744x1 cell} {300744x1 cell} {300744x1 cell}
ans =
1
??? Error using ==> cell2mat at 46
All contents of the input cell array must be of the same data type.
Error in ==> test at 5
T = cell2mat(C)
My question is how I can do that? The data is in the following link vessel-movements.csv. It contains numbers, as ids and coordinates, and timestamps.
As the error message says:
All contents of the input cell array must be of the same data type.
Columns 6, 7 and 8 are chars (datestrings). It's not possible to convert them into a Matrix. Leave them in a cell.
You can transform only the numerical data into a matrix: data = cell2mat(C(:,1:5)). The three left columns have to be converted with datenum() into a numerical time to add it to data matrix.
When you've got >=R2013b, you can use as datatype a table like: data = readtable('vessel-movements.csv');
I assume you only want to convert the first five columns of C, which are the ones that contain numeric data. You can use cell2mat as follows:
M = cell2mat(C(:,1:5));
or equivalently
M = [C{:,1:5}];
The main difference between a matrix and a cell array (in MATLAB parlance) is that a matrix holds elements of the same type and size, while a cell array holds elements of different types and sizes.
You read numbers and strings. The numbers do have the same type and size (double, 1×1) while the strings are different (they're all char type, but usually different sizes).
To group your numeric data, you must select only the numeric elements of your cell array:
N = horzcat(C{1:5});
while for the strings you should keep the cell array structure:
S = horzcat(C{6:8});
Later edit: Since you admit that you're new to MATLAB, I'm going to make a general recommendation: every time you see a function that you don't know what it does—or behaves unexpectedly from your point of view—mark its name and press F1. The MATLAB documentation is quite comprehensive, and contains also lots of examples depicting the typical uses for that function.
I have an cell including array as below format
a{x,y,z}(i,j)
a is 3 dimensional cell
and
each cell have i*j array
a <79x95x68 cell>
val(:,:,1) =
Columns 1 through 2
[6x6 double] [6x6 double]
[6x6 double] [6x6 double]
[6x6 double] [6x6 double]
i want to rearrange that as below format
a{i,j}(x,y,z)
how to? any good idea? i have to do iteration?
matlab say, a{:,:}(x,y,z) is bad cell referencing.........
here's a suboptimal way to go, it isn't memory efficient, but it is pretty straightforward:
say that x=79,y=95,z=68 are the dimensions of your original cell array, and that each of them gives the same dimensionality ixj matrix (6 by 6). So first you can make a matrix out of the cell array:
b=horzcat(a{:});
then we can reshape it to a 5-d array (this is just for pedagogical purposes) so you already have it ordered as (i,j,x,y,z)...
c=reshape(b,6,6,x,y,z);
then you can either work with c(i,j,x,y,z), or assign c to a cellarray:
d=cell(6,6);
for i=1:6
for j=1:6
d{i,j}=squeeze(c(i,j,:,:,:));
end
end
This question already has an answer here:
Convert cell array of cells into cell array of strings in MATLAB
(1 answer)
Closed 9 years ago.
I have a cell array of cell arrays of strings in matlab. I want to convert this to a simple list of unique strings so that I can access a string by its index in the list. What is the fastest way to do this?
Example -
C = {1x3 cell} {1x2 cell}
>> C{1}
ans = 'What's' 'up' 'man'
>> C{2}
ans = 'What's' 'there'
And I want a list of size 4 such that each index refers to a unique word - 'What's', 'up', 'man', 'there'. Not sure if this list should be cell array or matrix or what for it to be most efficient.
Here is the code to do what you need. You can use it for any size of array.
Cunq = unique(horzcat(C{:}),'stable');
You can call union on the cell arrays.
union(C{1},C{2})
If the order matters, add a third parameter:
union(C{1},C{2},'stable')
If I create a cell array using:
clear all
data = {rand(1,5),rand(1,4),rand(1,4),rand(1,6)};
a = cell(1,length(data));
how is it then possible to create a cell array in each cell of a which is the same length as the corresponding cell in data. I know this can easily be done using a loop, but how would it be possible by using the cellfun function?
Do you want something like that?
data = {rand(1,5),rand(1,4),rand(1,4),rand(1,6)};
a2=cellfun(#(x) cell(size(x)),data,'UniformOutput',0)
a2 =
{1x5 cell} {1x4 cell} {1x4 cell} {1x6 cell}
You could also accomplish this by using CELLFUN to just get the sizes of each cell, create all the cells you need, then divide them up using MAT2CELL:
>> cellSizes = cellfun('size',data,2);
>> a = mat2cell(cell(1,sum(cellSizes)),1,cellSizes)
a =
{1x5 cell} {1x4 cell} {1x4 cell} {1x6 cell}