How can I sort the elements of a cell?

丶灬走出姿态 提交于 2019-12-01 17:32:56

问题


I have a cell like this:

A{1,1}=[ 1 ;2; 3;];
A{2,1}=[ 4 ;2;];
A{3,1}=[ 3 ;2; 5; 4; 6;];
...
A{N,1}=[ 10 ;2;5; 7;];   %N is very large.

In other words, the number of columns in each element of this cell is different, with no definite pattern.

Now, I want to sort these elements based on the element at the first column. I mean, I want the result to be like this:

Asorted{1,1}=[ 1 ;2; 3;];
Asorted{2,1}=[ 3 ;2; 5; 4; 6;];
Asorted{3,1}=[ 4 ;2;];
...
Asorted{N,1}=[ 10 ;2;5; 7;];

Currently I use this function:

function Asorted = sortcell(A)
B=[];
nrows = size(A,1);

for i=1:nrows            % this for-loop is slow
    st=A{i,1};
    B(i,1) = st(1,1);
end
[sorted,indices] = sort(B);
Asorted = A(indices,:);
end 

It works, but it takes much time. In fact the for loop part is very slow.
I read about cat function, but I don't know how to use it. I used B = cat(1,A{:}(1,1));, but there is this error: ??? Bad cell reference operation.

I wanted to know if there is a more faster way of doing this?

Thanks.

Update Lets do an experiment:

A={};
for i=1:1e3
    A{i,1} = ones(4,1) * randn;
end

N=1000;sum1=0;sum2=0;sum3=0;sum4=0;
for t=1:N

    % # Solution with for loop and no prealocation
    tic
    B = [];
    for i = 1:size(A, 1)
        B(i, 1) = A{i,1}(1,1);
    end
    [Y, I] = sort(B);
    Asorted = A(I,:);
    a=toc;sum1=sum1+a;

    % # Solution with for loop and Prealocation
    tic
    B = zeros(size(A,1), 1);
    for i = 1:size(A, 1)
        B(i, 1) = A{i,1}(1,1);
    end
    [Y, I] = sort(B);
    Asorted = A(I,:);
    a=toc;sum2=sum2+a;

    % # Solution with cellfun
    tic
    [Y, I] = sort( cellfun( @(x) x(1), A ) );
    Asorted = A(I);
    a=toc;sum3=sum3+a;
    tic

    % # Solution with for loop and ???
    for i = 1:size(A, 1)
        B(i, 1) = A{i}(1);
    end
    [Y, I] = sort(B);
    Asorted = A(I);
    a=toc;sum4=sum4+a;
end

and the result is
sum1=2.53635923001387
sum2=0.629729057743372
sum3=4.54007401778717
sum4=0.571285037623497

** Which means per-allocation is faster, but what is the 4-th method. I thought it deserves to be discussed in a separate question. see Matlab Pre-allocation vs. no allocation, the second one is faster, why?


回答1:


Your loop is slow because B is growing inside it; you should preallocate memory for B and it should run significantly faster. To do this, insert the following line before the for loop:

B = zeros(nrows, 1);

You can further shorten your loop like so:

B = zeros(size(A,1), 1);
for i = 1:size(A, 1)
    B(i, 1) = A{i}(1);
end
[Y, I] = sort(B);
Asorted = A(I);

EDIT

I decided to compare this solution with a shorter solution that employs cellfun (which I formerly proposed):

A = {[1; 2; 3], [4; 2], [3; 2; 5; 4; 6], [10; 2; 5; 7]};

% # Solution with a for loop
tic
for jj = 1:1e3
    B = zeros(size(A,1), 1);
    for i = 1:size(A, 1)
        B(i, 1) = A{i}(1);
    end
    [Y, I] = sort(B);
    Asorted = A(I);
end
toc

% # Solution with cellfun
tic
for jj = 1:1e3
    [Y, I] = sort( cellfun( @(x) x(1), A ) );
    Asorted = A(I);
end
toc

The results are:

Elapsed time is 0.028761 seconds.
Elapsed time is 0.253888 seconds.

The loop runs by an order of magnitude faster than cellfun! This difference can be extremely noticeable for large arrays, so I recommend using a for loop in this problem.




回答2:


You can use cellfun

[~, I] = sort( cellfun( @(x) x(1), A ) );
Asorted = A(I);


来源:https://stackoverflow.com/questions/14021238/how-can-i-sort-the-elements-of-a-cell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!