我想生成这样的文件([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
我可以使用嵌套循环来执行此操作,如:
for i in $(seq 3)
do
for j in $(seq 5)
do
echo $i $j
done
done
有没有使用循环的解决方案?
答案 0 :(得分:12)
合并两个brace expansions!
$ printf "%s\n" {1..3}" "{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
这可以通过使用单支撑扩展来实现:
$ echo {1..5}
1 2 3 4 5
然后与另一个结合:
$ echo {1..5}+{a,b,c}
1+a 1+b 1+c 2+a 2+b 2+c 3+a 3+b 3+c 4+a 4+b 4+c 5+a 5+b 5+c
答案 1 :(得分:7)
正如@fedorqui指出的那样,bash中笛卡尔积的最佳选择肯定是使用参数扩展。但是,如果您的输入不易生成(即,如果{1..3}
和{1..5}
不够),您只需使用join
。
例如,如果要执行两个常规文件的笛卡尔积,请说“a.txt”和“b.txt”,则可以执行以下操作。首先,两个文件:
$ 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
请注意,sed
命令用于在每行前加一个标识符。所有行的标识符必须相同,和对于所有文件,因此join
将为您提供笛卡尔积 - 而不是放弃一些结果行。因此,join
如下:
$ 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
加入两个文件后,cut
用作删除之前预先添加的“1”列的替代方法。
答案 2 :(得分:7)
鲁本斯回答的一个较短(但很难)的版本:
join -j 999999 -o 1.1,2.1 file1 file2
由于字段999999很可能不存在,因此两个集合被认为是相等的,因此join
必须执行笛卡尔积。它使用O(N + M)内存,并在我的机器上以100..200 Mb /秒的速度产生输出。
对于大型数据集,我不喜欢像echo {1..100}x{1..100}
这样的“shell括号扩展”方法,因为它使用O(N * M)内存,并且在使用时可以不小心将机器置于膝盖。它很难停止,因为ctrl + c不会中断由shell本身完成的大括号扩展。