假设:
- 字符串
A,B,C被认为等价于A,C,B、B,A,C、B,C,A、C,A,B和C,B,A(即我们只需要生成这6种组合之一)
生成组合列表的一个想法...
- 我们将行加载到数组中
- 对于数组中的每个项目,我们将开始一组新的输出字符串
- 进行递归调用以将下一个数组项附加到我们的输出字符串
- 当我们将数组项附加到输出时,我们将继续打印包含 2 个或更多数组项的每个字符串
- 这更像是一种尾递归方法,它应该消除重复的生成(
A,B,C 与其他 5 个等效模式)和/或回滚“已经看到”组合的需要
一个awk 实现这个逻辑的想法:
awk '
# input params are current output string, current arr[] index, and current output length (ie, number of fields)
# parameter "i" will be treated as a local variable
function combo(output, j, combo_length, i) {
if ( combo_length >= 2) # print any combination with a length >= 2
print output
for (i=j+1; i<=n; i++) # loop through "rest" of array entries for next field in output
combo(output "," arr[i], i, combo_length+1 )
}
{ arr[NR]=$1 } # load fields into array "arr[]"
END { n=length(arr)
for (i=1; i<=n; i++) # for each arr[i] start a new set of combos starting with arr[i]
combo(arr[i],i,1)
}
' test.txt
这会生成:
A,B
A,B,C
A,B,C,D
A,B,D
A,C
A,C,D
A,D
B,C
B,C,D
B,D
C,D
如果我们想根据字段数排序,然后输出字符串,我们可以进行以下更改:
- 将
print output 更改为print combo_length, output 然后...
- 通过
sort | cut 管道awk 输出(我们将在此处借用格伦的代码)
这会生成:
$ awk ' ... print combo_length,output ...' test.txt | sort -k1,1nr -k2 | cut -d" " -f2-
A,B,C,D
A,B,C
A,B,D
A,C,D
B,C,D
A,B
A,C
A,D
B,C
B,D
C,D
对于 20 行 test.txt(字母 A 到 T),输出转储到文件 test.out:
$ time awk '...' test.txt > test.out
real 0m1.420s
user 0m1.279s
sys 0m0.139s
$ wc -l test.out
1048555 2097110 23685256 test.out
$ time awk '...' test.txt | sort ... | cut ... > test.out
real 0m3.456s
user 0m3.493s
sys 0m0.185s
$ wc test.out
1048555 1048555 20971480 test.out