Building all possible arrays from vector of subarrays. With recursion [duplicate] - arrays

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.

Related

Is there a matlab function for splitting an array for several array?

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

MATLAB: Remove specific elements from array

Question 1: I have a 1x15 array, comprising of positive integers and negative integers. I wish to implement a MATLAB code which keeps all positive integers and skips the cells with negative contents.
I have tried the following:
X = [1 2 3 4 5 -10 1 -5 4 6 8 9 2 4 -2];
[r c] = size(X);
for i=1:r
for j=1:c
if X(i,j)<0
X(i,j)=X(i,j+1)
end
end
end
The output should be:
X_new = [1 2 3 4 5 1 4 6 8 9 2 4]
How do I do this?
Question 2:
X = [1 2 3 4 5 -10 1 -5 4 6 8 9 2 4 -2]
Y = [5 3 8 9 4 5 6 7 4 7 9 5 2 1 4]
From Question 1,
X_new = [1 2 3 4 5 1 4 6 8 9 2 4]
I need to delete the corresponding values in Y so that:
Y_new = [5 3 8 9 4 6 4 7 9 5 2 1]
How do I perform this?
In MATLAB, manipulating arrays and matrices can be done much easier than for-loop solutions,
in your task, can do find and delete negative value in the array, simply, as follows:
Idx_neg = X < 0; % finding X indices corresponding to negative elements
X ( Idx_neg ) = []; % removing elements using [] operator
Y ( Idx_neg ) = []; % removing corresponding elements in Y array

Reshape the array along the reverse dimensions

>> 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.

Ordered random numbers in Matlab

I am trying to generate random numbers between 1 and 5 using Matlab's randperm and calling randperm = 5.
Each time this gives me a different array let's say for example:
x = randperm(5)
x = [3 2 4 1 5]
I need the vector to be arranged such that 4 and 5 are always next to each other and 2 is always between 1 and 3... so for e.g. [3 2 1 4 5] or [4 5 1 2 3].
So essentially I have two "blocks" of unequal length - 1 2 3 and 4 5. The order of the blocks is not so important, just that 4 & 5 end up together and 2 in between 1 and 3.
I can basically only have 4 possible combinations:
[1 2 3 4 5]
[3 2 1 4 5]
[4 5 1 2 3]
[4 5 3 2 1]
Does anyone know how I can do this?
Thanks
I'm not sure if you want a solution that would somehow generalize to a larger problem, but based on how you've described your problem above it looks like you are only going to have 8 possible combinations that satisfy your constraints:
possible = [1 2 3 4 5; ...
1 2 3 5 4; ...
3 2 1 4 5; ...
3 2 1 5 4; ...
4 5 1 2 3; ...
5 4 1 2 3; ...
4 5 3 2 1; ...
5 4 3 2 1];
You can now randomly select one or more of these rows using randi, and can even create an anonymous function to do it for you:
randPattern = #(n) possible(randi(size(possible, 1), [1 n]), :)
This allows you to select, for example, 5 patterns at random (one per row):
>> patternMat = randPattern(5)
patternMat =
4 5 3 2 1
3 2 1 4 5
4 5 3 2 1
1 2 3 5 4
5 4 3 2 1
You can generate each block and shuffle each one then and set them as members of a cell array and shuffle the cell array and finally convert the cell array to a vector.
b45=[4 5]; % block 1
b13=[1 3]; % block 2
r45 = randperm(2); % indices for shuffling block 1
r13 = randperm(2); % indices for shuffling block 2
r15 = randperm(2); % indices for shuffling the cell
blocks = {b45(r45) [b13(r13(1)) 2 b13(r13(2))]}; % shuffle each block and set them a members of a cell array
result = [blocks{r15}] % shuffle the cell and convert to a vector

Extract blocks of numbers from array in Matlab

I have a vector and I would like to extract all the blocks from it:
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4]
so that I will get vectors or a cell containing the blocks:
[1 1 1], [4 4], [5 5], [4], [6], [1], [2], [4 4 4], [9], [8], [4 4 4 4]
Is there an efficient way to do it without using for loops? Thanks!
You can use accumarray with a custom anonymous function:
y = accumarray(cumsum([true; diff(x(:))~=0]), x(:), [], #(x) {x.'}).';
This gives a cell array of vectors. In your example,
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4];
the result is
y{1} =
1 1 1
y{2} =
4 4
y{3} =
5 5
y{4} =
4
y{5} =
6
y{6} =
1
y{7} =
2
y{8} =
4 4 4
y{9} =
9
y{10} =
8
y{11} =
4 4 4 4
For loops aint as slow as you might think, especially not in more recent Matlab versions and especially not in our case. Maybe this will help
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4];
breakIdx = [0, find(diff(x)), length(x)];
groups = mat2cell(x,1,diff(breakIdx));
We find the groups by applying diff(x) and we get the group indices with find(). Then it's just a matter of moving the groups into the resulting cell groups.
There's very little edge case checks here so I recommend you add that.
If holding all blocks in a cell array is not so important, but ruther the full information about them, you can use this code:
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4];
elements = x(diff([0 x])~=0);
block_size = accumarray(cumsum(diff([0 x])~=0).',1).';
blocks = [elements; block_size];
to get a 2-row matrix with the element on the first row, and the block size on the second:
blocks =
1 4 5 4 6 1 2 4 9 8 4
3 2 2 1 1 1 1 3 1 1 4
Then define a function to create those blocks by need:
getBlock = #(k) ones(1,blocks(2,k))*blocks(1,k);
and call it with the number of block you want:
getBlock(8)
to get:
ans =
4 4 4

Resources