Print all possible combinations of an array of arrays - arrays

I want to take three files that each contain 80 or more lines of text and print all possible combinations of those three files.
For the sake of clarity, let's assume that
File1 contains
1
2
3
File2 contains
4
5
6
File3 contains
7
8
9
If I wanted to print only those combinations then there are many answers that I could use. However, as the files contain more lines that I care type manually into the Perl script. I am building an array from each file, then I build an array ref of those arrays. Finally I am attempting to use List::Permutor to print the combinations.
The problem I am getting is that I am printing out the memory references, and I cannot figure out how to dereference the arrays inside of the List::Permutor call.
Perl code
use List::Permutor;
use warnings;
open (FILE, app_txt);
chomp (#app = (<FILE>));
close (FILE);
open (FILE, att1_txt);
chomp (#att1 = (<FILE>));
close (FILE);
open (FILE, att2_txt);
chomp (#att2 = (<FILE>));
close (FILE);
my $permutor = List::Permutor->new( \#app, \#att1, \#att2);
while ( my #permutation = $permutor->next() ) {
print "#permutation\n";
}

I wrote Set::CrossProduct for this purpose.

It's not clear what you want.
Note that all the provided output of the snippets below are for the following inputs:
my #app = ( 1, 2, 3 );
my #att1 = ( 4, 5, 6 );
my #att2 = ( 7, 8, 9 );
If you want permutations of the arrays, your code works as-is.
use List::Permutor qw( );
my $permutor = List::Permutor->new( \#app, \#att1, \#att2);
while ( my #permutation = $permutor->next() ) {
say join ", ", map { "[#$_]" } #permutation;
}
Output:
[1 2 3], [4 5 6], [7 8 9]
[1 2 3], [7 8 9], [4 5 6]
[4 5 6], [1 2 3], [7 8 9]
[4 5 6], [7 8 9], [1 2 3]
[7 8 9], [1 2 3], [4 5 6]
[7 8 9], [4 5 6], [1 2 3]
If you want permutations of the contents of the arrays (regardless of the array from which a string originated), then you just need to create a list from the contents of the arrays.
use List::Permutor qw( );
my $permutor = List::Permutor->new( #app, #att1, #att2 );
while ( my #permutation = $permutor->next() ) {
say "#permutation";
}
Output:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 9 8
1 2 3 4 5 6 8 7 9
1 2 3 4 5 6 8 9 7
1 2 3 4 5 6 9 7 8
1 2 3 4 5 6 9 8 7
1 2 3 4 5 7 6 8 9
1 2 3 4 5 7 6 9 8
1 2 3 4 5 7 8 6 9
1 2 3 4 5 7 8 9 6
...
9 8 7 6 5 4 3 2 1
Keep in mind that P(80) is 100,000,000,000,000,000,000,000,000,000,000,000,000 times the number of atoms in the observable universe.
If you want all possible sets of a single element from each array, then you can use the following:
for my $app (#app) {
for my $att1 (#att1) {
for my $att2 (#att2) {
say "$app $att1 $att2";
}}}
or
use Algorithm::Loops qw( NestedLoops );
my $iter = NestedLoops([ \#app, \#att1, \#att2 ]);
while ( my ($app, $att1, $att2) = $iter->() ) {
say "$app $att1 $att2";
}
Output:
1 4 7
1 4 8
1 4 9
1 5 7
1 5 8
1 5 9
1 6 7
1 6 8
1 6 9
2 4 7
...
3 6 9

I solved my last issue with formatting, by cheating. I just edited the source files and removed all the \r and \n.
Final code:
use Algorithm::Loops qw( NestedLoops );
use warnings;
open (FILE, app_txt);
($app = (<FILE>));
close (FILE);
my #app = split /,/, $app;
open (FILE, att1_txt);
($att1 = (<FILE>));
close (FILE);
my #att1 = split /,/, $att1;
open (FILE, att2_txt);
($att2 = (<FILE>));
close (FILE);
my #att2= split /,/, $att2;
my $iter = NestedLoops([ \#app, \#att1, \#att2 ]);
while ( my ($app, $att1, $att2) = $iter->() ) {
open (my $fh, '>', 'test');
print $fh "$app $att1 $att2\n";
close $fh;
}
print "done\n";

Related

The inverse operation of tensor circular unfolding in Julia

I implemented Tensor Circular Unfolding (TCU) defined in this document (See Definition 2).
The TCU reshapes a tensor (or multidimensional array) X into a matrix (or two-dimensional array). By using TensorToolbox, I implemented that as follows:
using TensorToolbox
function TCU(X,d,k)
N = ndims(X)
#assert d < N
if d <= k
a = k-d+1
else
a = k-d+1+N
end
tenmat(permutedims(X,circshift(1:N,-a+1)),row=1:d)
end
for positive integers d<N and k≦N where N is the depth of input tensor X. The function tenmat comes from TensorToolbox.jl and it is for matricization of a tensor. Please see ReadMe file in TensorToolbox.jl.
Here I put an example with N=4.
X = rand(1:9,3,4,2,2)
#3×4×2×2 Array{Int64, 4}:
#[:, :, 1, 1] =
# 5 7 2 6
# 4 5 6 2
# 6 8 9 1
#
#[:, :, 2, 1] =
# 4 3 7 5
# 8 3 3 1
# 8 2 4 7
#
#[:, :, 1, 2] =
# 4 3 9 6
# 7 4 9 2
# 6 7 2 4
#
#[:, :, 2, 2] =
# 9 2 1 7
# 8 2 1 3
# 6 2 4 9
M = TCU(X, 2, 3)
#8×6 Matrix{Int64}:
# 5 4 4 7 6 6
# 7 3 5 4 8 7
# 2 9 6 9 9 2
# 6 6 2 2 1 4
# 4 9 8 8 8 6
# 3 2 3 2 2 2
# 7 1 3 1 4 4
# 5 7 1 3 7 9
What I need
I would like to write the reverse operation of the above function. That is, I need the function InvTCU that satisfies
X == InvTCU( TCU(X, d, k), d, k )
If we need, InvTCU can require the original tensor size size(X)
X == InvTCU( TCU(X, d, k), d, k, size(X) )
The reason why I need InvTCU
It is required in Equation (18) in the document to implement the algorithm named PTRC. In this situation, the size of the original tensor size(X) are available information.
EDIT
I added the description about tenmat.
I added the description that InvTCU can require the original tensor size.
Before giving the function, it might be noted that to get the matrixfied tensor, it is possible to use views instead of permuting the dimensions, which might be more efficient (depending on processing later). This can be done (I think) with the TrasmuteDims or TensorCast packages (https://docs.juliahub.com/TransmuteDims/NIYrh/0.1.15/).
Here is an attempt at a permutedims approach:
function invTCU(M,d,k, presize)
N = length(presize)
a = d<=k ? k-d+1 : k-d+1+N
X = reshape(M,Tuple(circshift(collect(presize),1-a)))
permutedims(X,circshift(1:N,a-1))
end
with this definition:
julia> X = reshape(1:48,3,4,2,2)
3×4×2×2 reshape(::UnitRange{Int64}, 3, 4, 2, 2) with eltype Int64:
[:, :, 1, 1] =
1 4 7 10
...
julia> X == invTCU(TCU(X, 2, 3), 2, 3, size(X))
true
seems to recover original tensor.

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

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

How to Apply Cellfun Vectors with Arrayfun, Matlab?

I am expanding the arrayfun code of the thread To Find Double Sequence With Transforms in Matlab? for a list of vectors in cellfun (DD).
Pseudocode
DD = {[9 1 5 6 6 6 5 1 1 0 7 7 7 7 7 8], [1 1 1 4], [7 7 7]};
d = cellfun(#(i) diff(diff([0 i 0]) == 0), DD, 'Uniform', false);
y = cellfun(#(z) ...
arrayfun(#(i,j) DD{i}(i:j), find(z>0), find(z<0), 'Uniform', false), ...
d, 'Uniform', false););
Expected output
y = { {[6 6 6], [1 1], [7 7 7]}, ...
{[1 1 1]}, ...
{[7 7 7]} };
Error
Index exceeds matrix dimensions.
Error in findDoubleSequenceAnonFunction>#(i,j)DD{i}(i:j)
Error in
findDoubleSequenceAnonFunction>#(z)arrayfun(#(i,j)DD{i}(i:j),find(z>0),find(z<0),'Uniform',false)
Error in findDoubleSequenceAnonFunction (line 5)
y = cellfun(#(z) ...
Comments
d = cellfun(.... I am applying the function diff(diff(... in cellfun. It should be ok.
y = cellfun(.... Need to have cellfun here because have the again a cell of vectors in d. Somehow, the cellfun-arrayfun is complicating.
How can you have cellfun-arrayfun combination here?
Just use a for-loop, easier to read:
XX = {[9 1 5 6 6 6 5 1 1 0 7 7 7 7 7 8], [1 1 1 4], [7 7 7]};
YY = cell(size(XX));
for i=1:numel(XX)
x = XX{i};
d = diff(diff([0 x 0]) == 0);
YY{i} = arrayfun(#(i,j) x(i:j), find(d>0), find(d<0), 'Uniform',false);
end
Result:
>> celldisp(YY)
YY{1}{1} =
6 6 6
YY{1}{2} =
1 1
YY{1}{3} =
7 7 7 7 7
YY{2}{1} =
1 1 1
YY{3}{1} =
7 7 7

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

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.

Resources