如何按第n个元素在v2.3中排序列表?

0 投票
2 回答
599 浏览
提问于 2025-04-16 12:34

这是我写的一个简单脚本:

#!/usr/bin/env python

file = open('readFile.txt', 'r')
lines = file.readlines()
file.close()
del file

sortedList = sorted(lines, key=lambda lines: lines.split('\t')[-2])

file = open('outfile.txt', 'w')
for line in sortedList:
    file.write(line)

file.close()
del file

它的功能是把一个文件改成这样的格式:

161788  group_monitor.sgmops    4530    1293840320  1293840152
161789  group_atlas.atlas053    22350   1293840262  1293840152
161790  group_alice.alice017    210     1293840254  1293840159
161791  group_lhcb.pltlhc15     108277  1293949235  1293840159
161792  group_atlas.sgmatlas    35349   1293840251  1293840160

(其中最后两个字段是时间戳)按倒数第二个字段的顺序排列成这样:

161792  group_atlas.sgmatlas    35349   1293840251  1293840160
161790  group_alice.alice017    210     1293840254  1293840159
161789  group_atlas.atlas053    22350   1293840262  1293840152
161788  group_monitor.sgmops    4530    1293840320  1293840152
161791  group_lhcb.pltlhc15     108277  1293949235  1293840159

如你所见,我使用了 sorted() 函数,这个函数是在版本2.4中引入的。我想知道如何把这个脚本改成适用于2.3版本,以实现同样的功能。

另外,我还想把时间戳转换成普通人能看懂的格式,这样生成的文件看起来像这样:

161792  group_atlas.sgmatlas    35349   01/01/11 00:04:11   01/01/11 00:02:40
161790  group_alice.alice017    210     01/01/11 00:04:14   01/01/11 00:02:39
161789  group_atlas.atlas053    22350   01/01/11 00:04:22   01/01/11 00:02:32

我知道可以用 strftime("%d/%m/%y %H:%M:%S", gmtime()) 来转换时间戳,但我就是搞不清楚怎么把它应用到脚本中,以便把文件改成那种格式。

有什么意见或建议吗?非常感谢!


@Mark: 更新

在某些情况下,时间戳是 3600,这表示某个任务没有完成。我想在这种情况下打印 aborted,而不是 01/01/1970。所以,我把 format_seconds_since_epoch() 改成了这样:

def format_seconds_since_epoch(t):
    if t == 3600:
        return "aborted"
    else:
        return strftime("%d/%m/%y %H:%M:%S",datetime.fromtimestamp(t).timetuple())

这样就解决了这个问题。这是能做的最好的吗?谢谢!!

2 个回答

1

针对你最后的问题,你可以通过 datetime.fromtimestamp 从类似 time_t 的“自纪元以来的秒数”值创建一个 datetime 对象,比如:

from datetime import datetime
from time import strftime

def format_seconds_since_epoch(t):
    return strftime("%d/%m/%y %H:%M:%S",datetime.fromtimestamp(t).timetuple())

print format_seconds_since_epoch(1293840160)

所以,把这个和稍微修改过的 pynator的回答结合起来,你的脚本可能看起来像这样:

#!/usr/bin/env python

from datetime import datetime
from time import strftime
import os

def format_seconds_since_epoch(t):
    return strftime("%d/%m/%y %H:%M:%S",datetime.fromtimestamp(t).timetuple())

fin = open('readFile.txt', 'r')
lines = fin.readlines()
fin.close()
del fin

split_lines = [ line.split("\t") for line in lines ]

split_lines.sort( lambda a, b: cmp(int(a[-2]),int(b[-2])) )

fout = open('outfile.txt', 'w')
for split_line in split_lines:
    for i in (-2,-1):
        split_line[i] = format_seconds_since_epoch(int(split_line[i]))
    fout.write("\t".join(split_line)+os.linesep)

fout.close()
del fout

注意,使用 file 作为变量名并不好,因为它会覆盖内置的 file 类型,所以我把它们改成了 finfout。(即使你之后用 del 删除这些变量,我觉得避免使用 file 这个名字还是个好习惯。)

关于你进一步询问的特殊“3600”值,你的解决方案是可以的。就我个人而言,我可能会保持 format_seconds_since_epoch 函数不变,这样就不会有让人意外的特殊情况,并且更通用。你可以创建一个额外的包装函数来处理这个特殊情况,或者只需将 split_line[i] = format_seconds_since_epoch(int(split_line[i])) 这一行改成:

entry = int(split_line[i])
if entry == 3600:
    split_line[i] = "aborted"
else:
    split_line[i] = format_seconds_since_epoch(entry)

... 不过我觉得两者之间的差别不大。

顺便说一下,如果这不是一次性的任务,我建议你使用比 2.3 更高版本的 Python 2 系列,因为 2.3 现在已经相当老了——新版本有很多不错的功能,可以帮助你写出更简洁的脚本。

4
file = open('readFile.txt', 'r')
lines = file.readlines()
file.close()
del file

lines = [line.split(' ') for line in lines]
lines.sort(lambda x,y: cmp(x[2], y[2])
lines = [' '.join(line) for line in lines]

当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。

撰写回答