我在一个文件中有这样的记录:
1867 121 2 56
1868 121 1 6
1868 121 2 65
1868 122 0 53
1869 121 0 41
1869 121 1 41
1871 121 1 13
1871 121 2 194我想要获得以下输出:
1867 121 2 56
1868 121 1 6
1868 121 2 65
1868 122 0 53
1869 121 0 41
1869 121 1 41
1870 121 0 0
1871 121 1 13
1871 121 2 194不同之处在于1870 121 0 0行。
因此,如果第一列中的数字之间的差异大于1,那么我们必须包括一行缺少数字的行(上面的例子是1870)和其他列。应该以某种方式获取其他列,即让第二列是该列编号的可能值中的最小值(在本例中,这些值可能是121或122),并且与第三列的情况相同。最后一列的值总是为零。
有人能给我提个建议吗?提前感谢!
我正在尝试用awk解决这个问题,但也许还有其他更好或更实用的解决方案……
发布于 2012-01-05 08:39:21
像这样的东西可能行得通-
awk 'BEGIN{getline;a=$1;b=$2;c=$3}
NR==FNR{if (b>$2) b=$2; if (c>$3) c=$3;next}
{if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print}' file file解释:
BEGIN{getline;a=$1;b=$2;c=$3} -在这个BEGIN块中,我们读取第一行,并将column 1中的值赋给变量a,将column 2赋值给变量b,将column 3赋值给变量column 2-
在这里,我们扫描整个文件(NR==FNR),跟踪column 2和column 3中可能的最低值,并将它们分别存储在变量b和c中。我们使用next来避免运行第二个pattern{action}语句。
{if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print} -此action语句检查column 1中的值,并将其与a进行比较。如果差值大于1,我们将执行for loop以添加所有缺少的行,并将a的值设置为$1。如果连续行的column 1中的值不大于1,我们将column 1的值赋给a并对其执行print。
测试:
[jaypal:~/Temp] cat file
1867 121 2 56
1868 121 1 6
1868 121 2 65
1868 122 0 53
1869 121 0 41
1869 121 1 41
1871 121 1 13 # <--- 1870 skipped
1871 121 2 194
1875 120 1 12 # <--- 1872, 1873, 1874 skipped
[jaypal:~/Temp] awk 'BEGIN{getline;a=$1;b=$2;c=$3}
NR==FNR{if (b>$2) b=$2; if (c>$3) c=$3;next}
{if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print}' file file
1867 121 2 56
1868 121 1 6
1868 121 2 65
1868 122 0 53
1869 121 0 41
1869 121 1 41
1870 120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1871 121 1 13
1871 121 2 194
1872 120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1873 120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1874 120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1875 120 1 12发布于 2012-01-05 17:05:45
Perl解决方案。应该也适用于大文件,因为它不会将整个文件加载到内存中,而是对文件进行两次遍历。
#!/usr/bin/perl
use warnings;
use strict;
my $file = shift;
open my $IN, '<', $file or die $!;
my @mins;
while (<$IN>) {
my @cols = split;
for (0, 1) {
$mins[$_] = $cols[$_ + 1] if $cols[$_ + 1] < $mins[$_ ]
or ! defined $mins[$_];
}
}
seek $IN, 0, 0;
my $last;
while (<$IN>) {
my @cols = split;
$last //= $cols[0];
for my $i ($last .. $cols[0]-2) {
print $i + 1, "\t@mins 0\n";
}
print;
$last = $cols[0];
}发布于 2012-01-05 21:37:27
Bash解决方案:
# initialize minimum of 2. and 3. column
read no min2 min3 c4 < "$infile"
# get minimum of 2. and 3. column
while read c1 c2 c3 c4 ; do
[ $c2 -lt $min2 ] && min=$c2
[ $c3 -lt $min3 ] && min=$c3
done < "$infile"
while read c1 c2 c3 c4 ; do
# insert missing line(s) ?
while (( c1- no > 1 )) ; do
((no++))
echo -e "$no $min2 $min3 0"
done
# now insert existing line
echo -e "$c1 $c2 $c3 $c4"
no=$c1
done < "$infile"https://stackoverflow.com/questions/8736039
复制相似问题