Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to produce cartesian product in bash?

Tags:

bash

seq

I want to produce such file (cartesian product of [1-3]X[1-5]):

1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
3 1
3 2
3 3
3 4
3 5

I can do this using nested loop like:

for i in $(seq 3) 
do
  for j in $(seq 5)
  do
      echo $i $j
  done
done

is there any solution without loops?

like image 202
Taher Khorshidi Avatar asked Apr 29 '14 11:04

Taher Khorshidi


People also ask

What is a Cartesian product in SQL?

Let’s learn it. A Cartesian product of two sets X and Y, denoted X × Y, is the set of all ordered pairs where x is in X and y is in Y. In terms of SQL, the Cartesian product is a new table formed of two tables. If those tables have 3 and 4 lines respectively, the Cartesian product table will have 3×4 lines.

How do you find the Cartesian product of empty sets?

Given two non-empty sets P and Q. The Cartesian product P × Q is the set of all ordered pairs of elements from P and Q, i.e., If either P or Q is the null set, then P × Q will also be empty set, i.e., P × Q = φ

How do you find the ordered pairs of Cartesian product tables?

If those tables have 3 and 4 lines respectively, the Cartesian product table will have 3×4 lines. Therefore, each row from the first table joins each row of the second table. You get the multiplication result of two sets making all possible ordered pairs of the original sets’ elements.

Is the Cartesian product of sets commutative?

(v) The Cartesian product of sets is not commutative, i.e. A × B ≠ B × A (vi) The Cartesian product of sets is not associative, i.e. A × (B × C) ≠ (A × B) × C (vii) If A is a set, then A × ∅ = ∅ and ∅ × A = ∅.


1 Answers

The best alternative for cartesian product in bash is surely -- as pointed by @fedorqui -- to use parameter expansion. However, in case your input that is not easily producible (i.e., if {1..3} and {1..5} does not suffice), you could simply use join.

For example, if you want to peform the cartesian product of two regular files, say "a.txt" and "b.txt", you could do the following. First, the two files:

$ echo -en {a..c}"\tx\n" | sed 's/^/1\t/' > a.txt
$ cat a.txt
1    a    x
1    b    x
1    c    x

$ echo -en "foo\nbar\n" | sed 's/^/1\t/' > b.txt
$ cat b.txt
1    foo
1    bar

Notice the sed command is used to prepend each line with an identifier. The identifier must be the same for all lines, and for all files, so the join will give you the cartesian product -- instead of putting aside some of the resultant lines. So, the join goes as follows:

$ join -j 1 -t $'\t' a.txt b.txt | cut -d $'\t' -f 2-
a    x    foo
a    x    bar
b    x    foo
b    x    bar
c    x    foo
c    x    bar

After both files are joined, cut is used as an alternative to remove the column of "1"s formerly prepended.

like image 126
Rubens Avatar answered Sep 26 '22 03:09

Rubens