如何使用Perl、Python或bash更改列中值的运行

2024-09-27 17:54:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我要遍历许多以制表符分隔的文件,并按以下方式更改单个列:

原件

Col1    Col2    ....
afawer  1
asdgf   1
aser    1
qwerq   10
a3awer  10
1sdgf   11
a55er   11
2wu9    12
asxwer  12
a2dgf   13
a1er    13
qperq   13
...

期望的替换

Col1    Col2    ....
afawer  1
asdgf   1
aser    1
qwerq   2
a3awer  2
1sdgf   3
a55er   3
2wu9    4
asxwer  4
a2dgf   5
a1er    5
qperq   5
...

请注意,Col2中的运行长度对于每个文件都有很大的不同,因此不能对长度进行硬编码。基本上,我要替换的模式是:

aaabbbbbccccdddd

其中a,b,c和d可以是任何整数。所需的替换为:

1112222233334444

以此类推(即整数的自然排序)。你知道吗

我想用Python或Perl来实现这一点,或者尽可能只使用bash命令,比如sed。你知道吗


Tags: 文件整数制表符col2col1qwerqaserasdgf
3条回答

awk你可以说:

awk 'NR>1{if ($2 == prev) { $2 = a; } else { prev=$2; a=a+1; $2=a; }}1' OFS='\t' filename

对于您的输入,它将产生以下输出:

Col1    Col2
afawer  1
asdgf   1
aser    1
qwerq   2
a3awer  2
1sdgf   3
a55er   3
2wu9    4
asxwer  4
a2dgf   5
a1er    5
qperq   5

对于Python,使用^{}对第二列上的行进行分组,并使用^{}提供的计数器:

import csv
from itertools import groupby
from operator import itemgetter

with open(inputfile, 'rb') as ifh, open(outputfile, 'wb') as ofh:
    reader = csv.reader(ifh, delimiter='\t')
    writer = csv.writer(ofh, delimiter='\t')
    writer.writerow(next(reader))  # copy across header

    for counter, (key, group) in enumerate(groupby(reader, itemgetter(1)), 1):
        for row in group:
            row[1] = counter
            writer.writerow(row)

这将使用相同的数据写入一个新的CSV文件,除了第二列被一个计数器(从1开始)替换,该计数器在第2列中的原始值每次更改时递增。你知道吗

这是一个非常简单的Perl解决方案。它只跟踪第二列的前一个值,如果它发生变化,它会改变$n的值。你知道吗

程序希望输入文件的路径作为命令行上的参数,并将修改后的数据发送到STDOUT。你知道吗

use strict;
use warnings;

print scalar <>; # Copy header line

my ($prev, $n) = (0, 0);
while (<>) {
  chomp;
  my @fields = split /\t/;
  ($prev, $fields[1]) = ($fields[1], $fields[1] == $prev ? $n : ++$n);
  print join("\t", @fields), "\n";
}

相关问题 更多 >

    热门问题