【发布时间】:2014-04-29 11:11:09
【问题描述】:
我想生成这样的文件([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
有没有没有循环的解决方案?
【问题讨论】:
我想生成这样的文件([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
有没有没有循环的解决方案?
【问题讨论】:
合并两个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..3} 与seq 3 或seq 1 3 相同,只是它带有shell。
echo {1..3}" "{1..5} | xargs -n 2。
echo {1..2}{3..4} 会产生完整的榆树叉积 13 14 23 24,而不是 1 23 24 或 13 23 4?
鲁本斯答案的较短(但 hacky)版本:
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 本身完成的大括号扩展。
【讨论】:
bash 中笛卡尔积的最佳替代方案肯定是——正如@fedorqui 所指出的——使用参数扩展。但是,如果您的输入不容易产生(即,如果{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”列的替代方法。
【讨论】: