输入数据基于第2列进行排序,如下所示:
1 100
1 101
1 200
3 360
4 800
4 950
4 952
使用示例数据,所需输出为:
1 200 3 360
4 800 4 950
4 800 4 952
也就是说,如果第2列中有值的行在范围内:value2大于value1 + 100&& value2小于value1 + 200。
我的尝试是:
awk 'BEGIN{FS="\t"; PREVLOC=$2; PREVLINE=$0}{ if($2>PREVLOC+200 || $2<PREVLOC+100 {PREVLOC=$2; PREVLINE=$0;} else {print PREVLINE"\t"$0; PREVLOC=$2; PREVLINE=$0;} }' inputfile
将前一行和上一行第2列保存到变量中以进行比较。但是,它并不适用于所有情况。使用示例数据,它不会打印最后一对。如果在它们之间存在一条线,其中第二列值例如是,则它也不会输出800-950对。 890。
目前,我已经用bash完全不同的方式解决了这个问题:
`while read var1 var2; do stuff with vars in awk; done<inputfile`
但它很慢。非常感谢任何帮助。
答案 0 :(得分:1)
我不知道这对你有多大的改进,因为它仍然是O(n^2)
算法,但它都是awk并值得一试。
有两个通行证。 NR==FNR
块是第一次传递并将整个文件读入内存(如果文件非常大,则另一个可能的问题,如果您担心性能,我猜它很大)。对于每一行,我们在第二遍中存储要测试的范围。
第二次传递逐行进行并扫描每组完整范围以找到符合条件的范围。
请注意,在调用awk时,您需要在命令行上提供两次输入文件,如图所示。
$ cat input.txt
1 100
1 101
1 200
3 360
4 800
4 950
4 952
$ cat b.awk
# first pass, load array with ranges
NR==FNR {range[$0] = ($2 + 100) ":" ($2 + 200); next}
# Here we process the file for the second time, looping through
# all ranges for every line of input
{
for (i in range) {
split(range[i], r, ":")
if ($2 > r[1] && $2 < r[2]) {
print i, $0
}
}
}
$ awk -f b.awk input.txt input.txt
1 200 3 360
4 800 4 950
4 800 4 952