I have two vectors a and b as an example:
a = [1 2 3 4];
b = [5 6 7 8];
I want to create strings from the indices of a and b:
c1 = a(1):b(1) = [1 2 3 4 5];
c2 = a(2):b(2) = [2 3 4 5 6];
c3 = a(3):b(3) = [3 4 5 6 7];
c4 = a(4):b(4) = [4 5 6 7 8];
Then I want to concatenate the obtained strings:
C = cat(2, c1, c2, c3, c4) = [1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8];
I would like a general solution to help me automatize this algorithm.
Solution
This should do the trick without using a loop:
>> a = [1 3 4 5];
>> b = [5 6 7 8];
>> resultstr = num2str(cell2mat(arrayfun(#(x,y) x:y,a,b,'UniformOutput',false)))
resultstr =
1 2 3 4 5 3 4 5 6 4 5 6 7 5 6 7 8
Performance
I tried to do a quick comparison between this method, Luis Mendo's method and the for loop (see e.g. A. Visser's answer). I created two arrays with pseudo-random numbers from 1 to 50 and 501 to 1000 and timed the calculation for array sizes from 1 to 300, disregarding the string conversion.
Luis Mendo's anwer is the clear winner, in terms of time complexity arrayfun seems to be on par with bsxfun. The for loop fares much worse, except for very small array sizes, but I'm not sure the timing can be trusted there.
The code can be found here. I'd be very happy to get some feedback, I'm a bit unsure about those measurements.
This can be done without loops (be they for, arrayfun or cellfun) using bsxfun's masking capability. This works also if the "strings" have different lengths, as in the following example.
a = [1 2 3];
b = [3 5 6];
m = (0:max(b-a)).'; %'
C = bsxfun(#plus, a, m);
mask = bsxfun(#le, m, b-a);
C = C(mask).';
The result in this example is:
C =
1 2 3 2 3 4 5 3 4 5 6
Try something like:
A = [1:5; 5:8];, C = [];
for i = A, C = [C i(1):i(2)]; end
Cstr = num2str(C);
I would do this:
a = [1 3 4 5]; b = [5 6 7 8];
c =[];
for i =1:length(a)
c = [c [a(i):b(i)]];
end
num2str(c)
First of all, don't assign variables as C1, C2, C3 etc, use cells for that.
I'd use a for-loop for this, though there probably is a better alternative.
a = [1 3 4 5]; b = [5 6 7 8];
C = [];
for ii = 1:length(a)
tmp = a(ii):b(ii);
C = [C tmp];
end
This way tmp stores your separate arrays, then the following line adds it to the pre-existing array C.
Just for fun:
a = [1 2 3 4]; b = [5 6 7 8];
A=fliplr(gallery('circul',fliplr([a,b])));
B=A(1:numel(a)+1,1:numel(a));
C=num2str(B(:).')
Related
I want to split an array into several arrays automatically. For example:
a=[1 2 3 4 5 6 7 8 9]
b=[2 5]
Thus, I want to split it to:
c1=[1 2]
c2=[3 4 5]
c3=[6 7 8 9]
How to do it?
A simple way is to use mat2cell:
a = [1 2 3 4 5 6 7 8 9];
b = [2 5];
c = mat2cell(a, 1, diff([0 b numel(a)]));
This gives a cell array c containing the subarrays of a:
>> celldisp(c)
c{1} =
1 2
c{2} =
3 4 5
c{3} =
6 7 8 9
I have a question that seems like it should have a simple answer that can avoid for loops.
Suppose I have an N x 4 array defined in MATLAB:
A = [1 2 3 4; 1 2 3 4; 1 2 3 4; 1 2 3 4; 1 2 3 4; 1 2 3 4];
In this example, N = 6, but it is arbitrary. I want to re-arrange A into a new array, B, which is 2 x 2 x N array of the form:
B(:,:,1) = [1 2; 3 4];
B(:,:,2) = [1 2; 3 4];
...
B(:,:,N) = [1 2; 3 4];
This seems like a simple problem and I tried a variety of things such as:
B = reshape(A',2,2,N);
However, this results in
B(:,:,1) = [1 3; 2 4];
B(:,:,2) = [1 3; 2 4];
...
B(:,:,N) = [1 3; 2 4];
I feel like there must be a simple way of doing this in one line using some combination of "reshape", "permute" and/or "transpose" that I am missing. Any suggestions are appreciated.
You are only missing a final permute. This is needed because Matlab is column-major, so it fills the new array down, then across:
B = permute(reshape(A.', 2,2,N), [2 1 3]);
>> A = [ 1 2 3 3 4 5 5 6 7 7 8 9 ];
>>
>> B = reshape(A, 2, 2, 3)
B(:,:,1) =
1 3
2 3
B(:,:,2) =
4 5
5 6
B(:,:,3) =
7 8
7 9
Since reshape can only change the size of the given array in the way of preserving the linear indices, however I would like to reshape the array along the reverse dimensions.
For example, convert A into
>> C = reverse-reshape(A, 2, 2, 3) % not required to be only one function
C(:,:,1) =
1 3
5 7
C(:,:,2) =
2 4
6 8
C(:,:,3) =
3 5
7 9
Is there any better method than writing loops and fill numbers one by one in version R2017b?
You would first reshape with the dimensions in reverse order, then swap the first and third dimensions with permute to reorder the elements so that they are populated in reverse order:
>> B = permute(reshape(A, 3, 2, 2), [3 2 1])
B(:,:,1) =
1 3
5 7
B(:,:,2) =
2 4
6 8
B(:,:,3) =
3 5
7 9
To do this in general independent of the matrix dimensions and assuming it is a 3D matrix, declare an array called dims that contains the output desired matrix size, reverse the elements and supply this into reshape:
dims = [2 2 3];
B = permute(reshape(A, fliplr(dims)), [3 2 1]);
fliplr reverses the elements in a matrix horizontally.
I have vector c:
c = [2 5 3];
I want to generate vectors with their lengths equal to each value in c in a consecutive order. So, I should obtain 3 vectors:
c1 = [1 2];
c2 = [3 4 5 6 7];
c3 = [8 9 10];
Next, I want to align these vectors in a 1x3 cell array:
out = {c1 c2 c3};
This may seem straightforward, but I can't figure how to do it automatically. Any ideas?
You could use mat2cell to accomplish this. We first create an array from 1 to sum(c) and then use mat2cell to group the array into pieces where each piece is the size of each element of c.
out = mat2cell(1:sum(c), 1, c);
This reduces the need for intermediate variables and gives you your cell array directly.
out{1} =
1 2
out{2} =
3 4 5 6 7
out{3} =
8 9 10
This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 8 years ago.
I'm trying to build all possible arrays of length n of a vector of n elements with at least 2 integers in each position. I should be getting 2^n combinations, 16 in this case. My code is generating only half of them, and not saving the output to an array
allinputs = {[1 2] [2 3] [3 4] [5 6]}
A = []
the command I run is
inputArray = inputBuilder(A,[],allinputs,1)
for the function
function inputArray = inputBuilder(A,currBuild, allInputs, currIdx)
if currIdx <= length(allInputs)
for i = 1:length(allInputs{currIdx})
mybuild = [currBuild allInputs{currIdx}(i)];
inputBuilder(A,mybuild,allInputs,currIdx + 1);
end
if currIdx == length(allInputs)
A = [A mybuild];
%debug output
mybuild
end
if currIdx == 1
inputArray = A;
end
end
end
I want all 16 arrays to get output in a vector. Or some easy way to access them all. How can I do this?
EDIT:
Recursion may be a requirement because allinputs will have subarrays of different lengths.
allinputs = {[1] [2 3] [3 4] [5 6 7]}
with this array it will be 1*2*2*3 or 12 possible arrays built
Not sure exactly if this is what you want, but one way of doing what I think you want to do is as follows:
allinputs = {[1 2] [2 3] [3 4] [5 6]};
comb_results = combn([1 2],4);
A = zeros(size(comb_results));
for rowi = 1:size(comb_results, 1)
indices = comb_results(rowi,:);
for idxi = 1:numel(indices)
A(rowi, idxi) = allinputs{idxi}(indices(idxi));
end
end
This gives:
A =
1 2 3 5
1 2 3 6
1 2 4 5
1 2 4 6
1 3 3 5
1 3 3 6
1 3 4 5
1 3 4 6
2 2 3 5
2 2 3 6
2 2 4 5
2 2 4 6
2 3 3 5
2 3 3 6
2 3 4 5
2 3 4 6
combn is here.