Elegant way to replicate a vector, placing it into each cell in a cell array

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

mycell = repmat({A},2,3)
Your MAT2CELL method properly pre-allocates a cell array, in the sense James Tursa is talking about. It can be written as a one-liner:
mycell = mat2cell(repmat(A,M,N),ones(1,M),ones(1,N)*length(A));
So does this, and it is much faster than the MAT2CELL method:
mycell = cellfun(@double,repmat({A},M,N),'Un',0);

Plus de réponses (2)

A=[1 2 3];
mycell=cell(2,3);
mycell(:)={A};

4 commentaires

@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?
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.
Thanks! Yes, I would like to initialize the cell array. Downstream, I will need to be able to alter the contents of the cells, so perhaps the shared reference copy to A is not the best. Thank you for your time!
@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.

Connectez-vous pour commenter.

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

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);
... 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.
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.
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.
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');
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?
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.
http://www.mathworks.com/matlabcentral/newsreader/view_thread/292183
cell array preallocation thread on CSSM.
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
Thank you, James! Your comments have enlightened me. And Thank you Sean for the link. I enjoyed reading it.

Connectez-vous pour commenter.

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!

Translated by