perl - all possible combinations of hash - perl

tell me how to get every possible combination of hash
Here is an example
my %data = (
'a' => [qw(a1 a2 a3)],
'b' => [qw(b1 b2 b3)],
'c' => [qw(c1 c2 c3)]);
to get
a1
a2
a3
b1
b2
b3
c1
c2
c3
a1 b1
a1 b2
a1 b3
a1 c1
a1 c2
a1 c3
b1 c1
b1 c2
b1 c3
b2 c1
b2 c2
b2 c3
b3 c1
b3 c2
b3 c3
a1 b1 c1
a1 b1 c2
a1 b1 c3
a1 b2 c1
a1 b2 c2
a1 b2 c3
a1 b3 c1
a1 b3 c2
a1 b3 c3
a2 b1 c1
a2 b1 c2
a2 b1 c3
a2 b2 c1
a2 b2 c2
a2 b2 c3
a2 b3 c1
a2 b3 c2
a2 b3 c3
a3 b1 c1
a3 b1 c2
a3 b1 c3
a3 b2 c1
a3 b2 c2
a3 b2 c3
a3 b3 c1
a3 b3 c2
a3 b3 c3
thanks

Use brian d foy's Set::CrossProduct module. You'll need to massage your hash into array of arrays in an obvious way.
use Set::CrossProduct;
my $iterator = Set::CrossProduct->new( ARRAY_OF_ARRAYS );
my $tuples = $iterator->combinations;

My module List::Gen contains a cartesian function that can produce the results you want. This code seems to do the trick, but your example does not contain all of the permutations that this will produce, which I am assuming is just an omission in the example.
use List::Gen 'cartesian';
my %data = (
'a' => [qw(a1 a2 a3)],
'b' => [qw(b1 b2 b3)],
'c' => [qw(c1 c2 c3)],
);
my $product = cartesian {join ' ' => sort grep defined, #_}
map {[#$_, undef]}
values %data;
say for sort {length $a <=> length $b or $a cmp $b} #$product;
That is a bit dense, so to explain:
values %data returns the arrays in %data
map {[#$_, undef]} then attaches an empty value to the end of each, since you want the partial combinations
cartesian {join ' ' => sort grep defined, #_} then does the meat of the work, computing the Cartesian product of the arrays while subtracting out the undefined elements, and sorting the values as your example shows.
sort {length $a <=> length $b or $a cmp $b} #$product then prints out the product in the order specified.

Related

creating a matrix by a vector in the following condition

I am trying to create a matrix in MATLAB by a vector in the following condition:
The vector is:
v=[a1; a2; a3; a4; a5; a1; a2; a3; a4; a5; a1; a2; a3; a4; a5; a1; a2; a3; a4; a5; a1; a2; a3; a4; a5; a1; a2; a3; a4; a5]
v is a vector of a1, a2, a3, a4, a5 elements that repeats 6 times in this example.
Now I need to make a matrix based on this vector such that:
matrix=
a1 a2 a3
a2 a1 a2
a3 a2 a1
a4 a3 a2
a5 a4 a3
a1 a2 a3
a2 a1 a2
a3 a2 a1
a4 a3 a2
a5 a4 a3
I make a gap between the two blocks of the matrix to show the concept.
The first column of the matrix is a1, a2, a3, a4, a5 (repeating two times).
The second column starts with a2 and decreases to a1, then increase again up to a4. so a2, a1, a2, a3, a4, repeat two times too.
The third column starts with a3...a1...a3 and repeats two times again.
So I need a for loop to make this matrix by the vector elements v.
I appreciate your help.
It is a rather particular sorting, so better define it directly. For example:
blockElements=[[1 2 3];[2 1 2];[3 2 1];[4 3 2];[5 4 3]];
matrixElements=[blockElements; blockElements];
Then the matrix you want is just:
matrix=v(matrixElements);
Note that for this to work you don't need v to repeat 6 times a1...a5. It would work also if v is defined like
v=[a1; a2; a3; a4; a5];
or
v=[a1, a2, a3, a4, a5];
Actually, I don't see a straightforward approach for producing that result using a one-liner function; reshaping is a good solution only as long as elements are already placed properly inside the vector... which is not the case, hence the repetition of the values in the vector is kinda useless. On the top of that, I don't see the point of using a for loop to achieve this result when you can use straighe indexing.
v = 40:45; % if it's really mandatory you can use repmat(40:45,1,6)
m = [v(repmat(1:5,1,2)).' v(repmat([2 1 2 3 4],1,2)).' v(repmat([3 2 1 2 3],1,2)).'];
m =
40 41 42
41 40 41
42 41 40
43 42 41
44 43 42
40 41 42
41 40 41
42 41 40
43 42 41
44 43 42

Spark: grouping rows in array by key

I have a spark dataset like this one:
key id val1 val2 val3
1 a a1 a2 a3
2 a a4 a5 a6
3 b b1 b2 b3
4 b b4 b5 b6
5 b b7 b8 b9
6 c c1 c2 c3
I would like to group all rows by id in a list or array like this:
(a, ([1 a a1 a2 a3], [2 a a4 a5 a6]) ),
(b, ([3 b b1 b2 b3], [4 b b4 b5 b6], [5 b b7 b8 b9]) ),
(c, ([6 c c1 c2 c3]) )
I have used map to output key/value pairs with the right key but I have troubles in building the final key/array.
Can anybody help with that?
how about this:
import org.apache.spark.sql.functions._
df.withColumn("combined",array("key","id","val1","val2","val3")).groupby("id").agg(collect_list($"combined"))
The Array function converts the columns into an array of column and then its a simple groupby with collect_list
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.sql.functions._
val assembler = new VectorAssembler()
.setInputCols(Array("key", "id", "val1", "val2", "val3","score"))
.setOutputCol("combined")
val dfRes = assembler.transform(df).groupby("id").agg(collect_list($"combined"))
File Content of my xzy.txt file
key id val1 val2 val3
1 a a1 a2 a3
2 a a4 a5 a6
3 b b1 b2 b3
4 b b4 b5 b6
5 b b7 b8 b9
6 c c1 c2 c3
Code with Required Output
Input file Content

transform matrix and repeat values

I have this matrix:
a1 a2 a3 a4 a5
b1 b2 b3 b4 b5
c1 c2 c3 c4 c5
d1 d2 d3 d4 d5
e1 e2 e3 e4 e5
and i need to transform it to this matrix:
a1 a2 a3 b1 b2 b3 c1 c2 c3
a2 a3 a4 b2 b3 b4 c2 c3 c4
a3 a4 a5 b3 b4 b5 c3 c4 c5
b1 b2 b3 c1 c2 c3 d1 d2 d3
b2 b3 b4 c2 c3 c4 d2 d3 d4
b3 b4 b5 c3 c4 c5 d3 d4 d5
c1 c2 c3 d1 d2 d3 e1 e2 e3
c2 c3 c4 d2 d3 d4 e2 e3 e4
c3 c4 c5 d3 d4 d5 e3 e4 e5
i.e. by taking a 3x3 matrix and iterating over the old matrix putting it as a new row in the new matrix.
How can i do this in matlab? I heard loops are very bad and if I can I should use matrix operations.
If you have access to image processing toolbox you can use im2col which even works for symbolic variables too.
A = sym('A%d%d', [5 5]);
A = sym(A, 'real');
Subs = mat2cell(im2col(A, [3 1])', 3*ones(1,5));
Res = im2col(Subs, [3 1]);
Res is a cell matrix containing the sub matrices.
To concatenate it into a matrix:
reshape([Res{:}]', [9 9])
or if it's not symbolic this also works: cell2mat(Res).
Take a look at this code :
clear
clc
a1 = 1; a2 = 2; a3 = 3; a4 = 4; a5 = 5;
b1 = 11; b2 = 12; b3 = 13; b4 = 14; b5 = 15;
c1 = 21; c2 = 22; c3 = 23; c4 = 24; c5 = 25;
d1 = 31; d2 = 32; d3 = 33; d4 = 34; d5 = 35;
e1 = 41; e2 = 42; e3 = 43; e4 = 44; e5 = 45;
A = [a1 a2 a3 a4 a5; b1 b2 b3 b4 b5; c1 c2 c3 c4 c5; d1 d2 d3 d4 d5; e1 e2 e3 e4 e5];
B = zeros(9,9);
sizeA = size(A);
sizeB = size(B);
jj = 1;
kk = 1;
for ii = 1 : sizeB(1)
B(ii,1:sizeB(1)) = [A(kk, jj:jj+2) A(kk + 1, jj:jj+2) A(kk + 2, jj:jj+2)]
jj = jj + 1;
if mod(ii,3) == 0
kk = kk + 1;
jj = 1;
end
end
I tested it for your case where A is 5x5 and B is 9x9. Might need to be modified to work with different size of A and B.
You can do this in a somewhat general sense, but it is not pretty:
a = [a1, a2, a3, a4, a5];
b = [b1, b2, b3, b4, b5];
% etc.
% Rearrange your vector into a matrix configured how you want it
A = flipdim(toeplitz(a),1); % 5 x 5 matrix in our case
A = A(ceil(size(A,1)/2):size(A,1), ceil(size(A,2)/2):size(A,2)); % now 3 x 3
%%%
% Repeat similar process for b --> B, c --> C, etc.
%%%
% Build the resulting matrix up block-by-block
M = [A, B, C;
B, C, D;
C, D, E];
I was unable to find a good way to generalize the construction of M, and unfortunately forming a toeplitz matrix using toeplitz([a,b,c,d,e]) fails; you do not get the right format for your sub-matrices. Still, you may be able to use this to start on something.

complex looping using Matlab

Let there be five matrices given as:
A= [A1 A1 A1 A1 A1; A2 A2 A2 A2 A2; A3 A3 A3 A3 A3]
B= [B1 B1 B1 B1 B1; B2 B2 B2 B2 B2;B3 B3 B3 B3 B3]
C=[ C1 C1 C1 C1 C1; C2 C2 C2 C2 C2; C3 C3 C3 C3 C3]
D= [D1 D1 D1 D1 D1 ; D2 D2 D2 D2 D2; D3 D3 D3 D3 D3]
E=[ E1 E1 E1 E1 E1; E2 E2 E2 E2 E2; E3 E3 E3 E3 E3]
I want to make a program such that ouput consists of taking each row of each given matrix and forming a new matrix. how to use looping in such cases when length of matrices increases and number of given matrices also increases. This problem seemed to me a complex one. Because I want to generalize by using loop and output for any number of matrices say 20 and having number of columns also increased to say 25, then how to get these P1 to P20 outputs. Can anyone help me regarding this complex trouble using Matlab
P1=[ A1 A1 A1 A1 A1; B1 B1 B1 B1 B1; C1 C1 C1 C1 C1 C1; D1 D1 D1 D1 D1; E1 E1 E1 E1 E1]
P2=[ A2 A2 A2 A2 A2; B2 B2 B2 B2 B2; C2 C2 C2 C2 C2 C2; D2 D2 D2 D2 D2; E2 E2 E2 E2 E2]
and similarly other matrices is obtained .
Note: That the given 5 matrices are generated with help of loop. So first I would be getting values as :
A= A1
B= B1
C=C1
D=D1
E=E1
A= A1 A1
B= B1 B1
C=C1 C1
D=D1 D1
E=E1 E1 .... AND SO ON
Get a loop and put all the matrix together to form a 3D tensor. Or just put the matrices in the 3D tensor when they are created.
M(:,:,1) = A; M(:,:,2) = B; etc
then
squeeze(M(1,:,:))' is the P1, squeeze(M(2,:,:))' is the P2
Example:
M(:,:,1) =
1 2
3 4
M(:,:,2) =
5 6
7 8
>> squeeze(M(1,:,:))'
ans =
1 2
5 6

MATLAB: Combine matrices with different length but some identical entries in one column

Suppose I have measured two variables a and b with a different temporal resolution, e.g. I have a 7x2 matrix A (headers only for illustration):
time value
t1 a1
t2 a2
t3 a3
t4 a4
t5 a5
t6 a6
t7 a7
and a 3x2 matrix B:
time value
t2 b1
t4 b2
t6 b3
Is there an elegant way (i.e without looping find) to combine them in a 3x2 matrix C that only includes times where I have measured both a and b:
time value a value b
t2 a2 b1
t4 a4 b2
t6 a6 b3
?
Perform set intersection:
[~,IA,IB]=intersect(A(:,1),B(:,1),'rows');
C=[A(IA,:) B(IB,2)];