Elegant way to replicate a vector, placing it into each cell in a cell array
Afficher commentaires plus anciens
Hi,
I would like to be able to create a cell array, with each cell containing the same 1 by 3 vector that I specify. For example, suppose that I have the following:
A=[1 2 3];
and suppose that I want to obtain the following:
mycell={[1 2 3],[1 2 3],[1 2 3];[1 2 3],[1 2 3],[1 2 3]};
Is there an elegant way to do this? It is as if I would like a sort of "repcell" function, similar to the repmat function. I am not sure if one exists, though.
I could do this:
tic
mycell=cell(2,3);
for i=1:1:size(mycell,1)
for j=1:1:size(mycell,2)
mycell{i,j}=A;
end
end
toc
and I get "Elapsed time is 0.000956 seconds." Or I could do:
tic
myarray=repmat(A,2,3);
mycell=mat2cell(myarray,[1 1],[3 3 3]);
toc
and I get "Elapsed time is 0.029993 seconds."
Either one of these seems like it will work fine for me, even when I want my cell array to be very large. Still, I am wondering, is there a more elegant way to do this (even in terms of code readability)?
Thank you very much for your time.
Andrew DeYoung
Carnegie Mellon University
Réponse acceptée
Plus de réponses (2)
Fangjun Jiang
le 7 Juin 2011
A=[1 2 3];
mycell=cell(2,3);
mycell(:)={A};
4 commentaires
James Tursa
le 7 Juin 2011
@Andrew: This method is not equivalent to a repmat operation. What this will do is create a cell array of references, each reference pointing back to the original A. I.e., each cell will be a shared reference copy (for lack of a better term) of the original A. When you subsequently alter one of the cells, then a copy will be made of the contents at that time if necessary. So if you plan on changing the contents of your cells after you have created mycell via the above method, it may be a total waste of time and effort. What are you intending to do with mycell downstream after it is created?
Fangjun Jiang
le 7 Juin 2011
My guess would be that Andrew wants to initialize the cell array, like pre-allocate memory. In that case, what will be the best approach? Or is it even necessary or possible to pre-allocate a cell array.
Andrew
le 7 Juin 2011
James Tursa
le 7 Juin 2011
@Andrew: I am still not clear what you are doing downstream with mycell. Are you *replacing* cells with a completely different variables, or are you replacing only certain *elements* of the cell contents with different value? i.e., are you doing something like:
mycell{k} = something_else
Or are you doing something like:
mycell{k}(m) = some_value
If it is the former, then pre-allocating mycell with variable contents ala repmat and the like makes no sense whatsoever, and you would be better off pre-allocating an empty cell array and then filling the contents downstream as you go.
Fangjun Jiang
le 7 Juin 2011
I am not trying to win a competition but here is the example. It looks like it will be faster to pre-allocate using hidden reference than using the repmat().
>> clear all;
A=1:3;
tic;
mycell=cell(10000,1);
mycell(:)={A};
for k=length(mycell)
mycell{k}=rand(1,3);
end
toc;
clear all;
A=1:3;
tic;
mycell=repmat({A},10000,1);
for k=length(mycell)
mycell{k}=rand(1,3);
end
toc;
Elapsed time is 0.003057 seconds.
Elapsed time is 0.012636 seconds.
And it is still the case if the loop is mycell{k}(2)=rand;
10 commentaires
James Tursa
le 7 Juin 2011
What are those for loops supposed to be doing? They only iterate once. Also, even if you changed them to iterate over the entire contents of mycell they would simply be replacing the contents of mycell, so I don't see what it is adding to the timing discussion. And I will reiterate my earlier point that doing either of these:
mycell=cell(10000,1);
mycell(:)={A};
or
mycell=repmat({A},10000,1);
is basically wasteful and pointless unless the downstream code is accessing the individual elements ala mycell{k}(m) or similar. If you are just going to replace all of the cells themselves with something else entirely then the only thing worth doing is this:
mycell = cell(10000,1);
Matt Fig
le 8 Juin 2011
... As shown by:
M = 100;
N = 100;
A = 1:3000;
tic
mycell = cell(M,N); % Pre-allocate
mycell(:)={A};
for k=1:M*N
mycell{k} = rand(1,3000); % Fill it up.
end
toc
tic
mycell2 = repmat({A},M,N); % Pre-allocate
for k=1:M*N
mycell2{k} = rand(1,3000); % Fill it up.
end
toc
tic
mycell3 = cell(M,N); % Pre-allocate
for k=1:M*N
mycell3{k} = rand(1,3000); % Fill it up
end
toc
On my machine:
Elapsed time is 0.468874 seconds.
Elapsed time is 0.471699 seconds.
Elapsed time is 0.461892 seconds.
Fangjun Jiang
le 8 Juin 2011
Okay, thank you both, James and Matt!
I've tried Matt's code in two variations. One is to do the loop accessing mycell{k}(m). The second is not to pre-allocate mycell at all (not even using mecell=cell(M,N)). There is no significant difference in CPU time. Points taken:
1. There is no need to pre-allocate cell array by filling its content.
2. There is no need to pre-allocate cell array at all.
Of course, there might be a good reason to pre-fill the content of a cell array for the purpose of setting its initial value with one or two lines.
James Tursa
le 8 Juin 2011
I don't technically agree with your point 2. If you don't pre-allocate the cell at all, and you have a downstream loop that is filling the contents, then you will be growing the cell array size in a loop and that causes a data copy to take place each iteration (the data in this case being the cell variable pointers). For small cell array sizes the timing difference will not be much, but for large cell array sizes I see no reason to throw away the timing with all that unnecessary data thrashing. I would opt to always pre-allocate.
Fangjun Jiang
le 8 Juin 2011
I understand the need and benefit of pre-allocating data array. But I thought I also read somewhere that cell array is different. The storage of cell array is not necessarily consecutive because its content can be any type and any size. I tried the code below. The difference is significant when L=3 but not that much when L=3000.
clear all;
M=100;
N=100;
L=3000;
tic;
MyCell=cell(M,N);
for k=1:M*N
MyCell{k}=rand(1,L);
end
toc;
clear MyCell k;
tic;
for k=1:M*N
MyCell{k}=rand(1,L);
end
toc;
fprintf('\n');
Matt Fig
le 8 Juin 2011
Fangjun, I see a significant difference in timing with no pre-allocation whatsoever (about 50% increase in time). I am using 2007b, perhaps you are using 2011a?
Fangjun Jiang
le 8 Juin 2011
R2007b+, L=3000
Elapsed time is 0.854775 seconds.
Elapsed time is 1.189363 seconds.
R2007b+, L=3
Elapsed time is 0.011271 seconds.
Elapsed time is 0.164387 seconds.
R2010b,L=3000
Elapsed time is 0.756074 seconds.
Elapsed time is 0.941522 seconds.
R2010b,L=3
Elapsed time is 0.011895 seconds.
Elapsed time is 0.144747 seconds.
Sean de Wolski
le 8 Juin 2011
http://www.mathworks.com/matlabcentral/newsreader/view_thread/292183
cell array preallocation thread on CSSM.
James Tursa
le 8 Juin 2011
The data storage layout for a cell array is *exactly* the same as the data storage layout for all other variables ... the data is contiguous in memory. But the "data" for a cell array in this context is variable pointers. So, yes, the actual content of the cells themselves are not in general contiguous in memory (the variables being pointed to are not contiguous), but the *pointers* to these variables, which is what is physically stored in the cell array data area, *are* contiguous in memory. It is *that* memory that gets constantly copied and re-copied in a loop that increases the size of the cell array if you don't pre-allocate the cell array. The L in your above code has nothing to do with this since it only affects the cell variables and not the physical cell array data area. e.g., to see the effect isolated:
n = 100000;
A = 1:3;
clear mycell1
tic
mycell1 = cell(1,n); % pre-allocated
for k=1:n
mycell1{k} = A; % not growing in a loop
end
toc
clear mycell2
tic
for k=1:n
mycell2{k} = A; % growing in a loop
end
toc
isequal(mycell1,mycell2)
Elapsed time is 0.049412 seconds.
Elapsed time is 27.087694 seconds.
ans =
1
Fangjun Jiang
le 8 Juin 2011
Thank you, James! Your comments have enlightened me. And Thank you Sean for the link. I enjoyed reading it.
Catégories
En savoir plus sur Performance and Memory dans Centre d'aide et File Exchange
Produits
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!