更改第一列中的数字

1 投票
5 回答
953 浏览
提问于 2025-04-16 09:38

我知道用sed或awk可以更优雅地解决这个问题。不过我选择了用Python来处理。我的问题是,我想把数据文件的第一列重新编号,从1开始,一直到文件的行数。这种做法用readlines读取文件是否合适呢?对于小文件来说可能可以,但对于大文件我觉得不太行。所以这是我第一次尝试的结果,欢迎大家给我提意见。

#!/usr/bin/env python

import sys

try:
    infilename = sys.argv[1]; outfilename = sys.argv[2];
except:
    print "Usage is <script> inFile outFile"

ifile = open(infilename,'r')
ofile = open(outfilename, 'w')

lines = ifile.readlines();

i=1
for line in lines: 
    list = line.split();
    list[0] = i
    i += 1 
    for val in list:
        ofile.write("%d " % int(val))
    ofile.write('\n')
    del list

ifile.close()
ofile.close()

5 个回答

1

在编程中,有时候我们需要处理一些数据,比如从一个地方获取数据,然后把它放到另一个地方。这就像是把水从一个杯子倒到另一个杯子一样。

当我们在写代码的时候,可能会遇到一些问题,比如数据的格式不对,或者数据没有按照我们想要的方式出现。这就像是你想喝水,但杯子里却是果汁,这时候你就需要想办法把果汁换成水。

有时候,程序会给我们一些错误提示,这些提示就像是一个指南,告诉我们哪里出了问题。我们需要仔细阅读这些提示,找到解决问题的方法。

总之,编程就像是在解决一个个小难题,我们需要耐心和细心,才能把这些问题一个个解决掉。

with open(infilename,'r') as ifile:
    with open(outfilename, 'w') as ofile:
         for (nr, line) in enumerate(ifile):
             line = line.split()
             line[0] = nr
             line.append('\n')
             ofile.write(' '.join(line))
1
#!/usr/bin/env python
import sys

try:
    ifile = open(sys.argv[1], 'r')
    ofile = open(sys.argv[2], 'w+')
except:
    print "Usage is <script> inFile outFile"
else:
    for i, line in enumerate(ifile, start=1):
        items = [str(i)] + line.split()[1:]
        ofile.write(' '.join(items) + '\n')

    ifile.close()
    ofile.close()

我想和大家聊聊我这个答案中的几个要点。首先是“try”块,这里我在检查能否打开文件。如果没有输入文件名,或者有文件无法打开,你就会看到使用说明。其实你可以把这个过程分开:先检查输入的文本,如果没有就返回使用说明;再尝试打开文件,如果失败了就返回文件打开失败的提示。或者,你也可以检查特定的错误类型,返回不同的错误信息。

接下来,枚举是一种方便的方式,可以让程序自动跟踪索引。在循环中,我把枚举的索引和读取行的“切片”(除了第一个项目以外的所有内容)结合在一起。然后我用空格把它们连接起来,并在最后加上换行符。

这样做既清晰又简洁。

1

你可以通过遍历文件,只在内存中保留当前行:

#!/usr/bin/env python
import sys

try:
    # dont use ; !
    infilename = sys.argv[1]
    outfilename = sys.argv[2]
except:
    print "Usage is <script> inFile outFile"


# you could use `with` here if you have a Python 2.7
ifile = open(infilename,'r')
ofile = open(outfilename, 'w')

# no need to count yourself, enumerate does that
# plus when you iterate over a file you get lines too
for i, line in enumerate(ifile, start=1):
    # dont shadow builtins like `list`
    parts = line.split()
    parts[0] = i
    # join is the inverse function to split
    new_line = ' '.join("%d" % int(val) for val in parts)
    ofile.write(new_line + '\n')

ifile.close()
ofile.close()

@Umut Tabak: ("%d" % int(val) for val in parts) 是一种叫做 生成器表达式 的东西,它有点像懒惰的列表。它给出的结果和列表推导式 ["%d" % int(val) for val in parts] 是一样的,但它并不会真正创建一个列表。

顺便说一下,for 循环的写法可以更简短,但稍微有点不同,因为它不再强制要求所有行都是 int 类型了:

for i, line in enumerate(ifile, start=1):
    parts = line.split()
    parts[0] = "%d" % i
    new_line = ' '.join(parts)
    ofile.write(new_line + '\n')

撰写回答