将文本文件中的行数从最大到最小排序?

时间:2018-01-18 18:58:51

标签: python regex python-3.x list sorting

我有一个看起来像的文本文件:

Josh123: Level 2
Marcus N: Level 4
Callie [L16]: Level 1
Ashley 4: Level 3

我想要的是它会按照各自的等级对它们进行排序并打印出来,就像这样:

Marcus N: Level 4
Ashley 4: Level 3
Josh123: Level 2
Callie [L16]: Level 1

有办法做到这一点吗?谢谢!

6 个答案:

答案 0 :(得分:0)

有很多方法。这是一个简单的:

with open("myFile") as lines:
    print(''.join(reversed(sorted(lines, key = lambda line:int(line.split()[-1])))))

稍微强一些的方式:

import re
def getLevel(line):
    match = re.search('Level ([0-9]+)', line)
    if match:
        return int(match.groups()[0])
    return 0

with open("myFile") as lines:
    print(''.join(reversed(sorted(lines, key = getLevel))))

这将在末尾放置与“Level N”不匹配的行。将return 0替换为return 9999或类似内容,将其置于开头。

另请参阅Thomas Howard's answer below以获得更好的选择。

答案 1 :(得分:0)

你可以试试这个:

import re
with open('filename.txt') as f:
  data = [i.strip('\n') for i in f]
final_data = '\n'.join(map(lambda x:x[0], sorted(zip(data, [int(re.findall('(?<=Level\s)\d+', i)[0]) for i in data]), key=lambda x:x[-1], reverse=True)))

输出:

Marcus N: Level 4
Ashley 4: Level 3
Josh123: Level 2
Callie [L16]: Level 1

答案 2 :(得分:0)

你可以去

import re

string = """
Josh123: Level 2
Marcus N: Level 4
Callie [L16]: Level 1
Ashley 4: Level 3
"""

rx = re.compile(r'.+Level (\d+)')

# create the list of tuples and sort em
sorted_students = sorted([(match.group(0), int(match.group(1))) 
        for match in rx.finditer(string)], 
        key = lambda x: x[1], reverse = True)

# join the first item of every tuple with \n
student = "\n".join(student[0] for student in sorted_students)
print(student)

哪个收益

Marcus N: Level 4
Ashley 4: Level 3
Josh123: Level 2
Callie [L16]: Level 1

<小时/> 这里的想法是与Level [some digits here]的每一行匹配,然后转换数字并按此排序。最后,再次将结果与\n联系起来。

答案 3 :(得分:0)

另一种更强大的方法是实际构建用户对象,将它们存储在列表中,然后对其进行排序。它是可扩展的,如果你添加其他字段,你可以轻松地构建namedtuples:

""" Sort players by level

Read a text file, each line represents a user.
Sort these users by level in reversed order.
"""
import re
from collections import namedtuple

User = namedtuple('User', ['level', 'info']) # Named tuple stores user information.
LEVEL_PATTERN = re.compile(r'Level (?P<level>\d+)$') # This finds the users level, compiled only once.

users = [] # A place to hold the users

# Read players in
with open('players.txt') as players:
    for player in players:
        level = re.search(LEVEL_PATTERN, player).group('level')
        users.append(User(level, (player.strip())))

# Sort, and print
for player in sorted(users, key=lambda player: int(player.level), reverse=True): # timeit 2.88, n=1000
    print(player.info)

最佳

编辑使用点符号和数字排序而不是词典。

另请注意,可以移动此代码段的int()部分。例如,可以在首次保存级别时放置它,而不是在lambda表达式中放置:

for player in players:
    level = int(re.search(LEVEL_PATTERN, player).group('level'))
    users.append(User(level, (player.strip())))

或者,当创建nampedtuple时:

level = re.search(LEVEL_PATTERN, player).group('level')
users.append(User(int(level), (player.strip()))) # tiemit 2.06, n=1000

从理论上讲,实际上,上述方法更快。根据我的有限样本,根据timeit,每个循环的速度快〜0.8。

这是有道理的,因为在比较期间进行转换可以比在摄入时进行更多转换。在分拣过程中每次比较需要更多时间。

此外,由于没有排序算法达到O(n),因此摄入转换是更好的方法。

答案 4 :(得分:0)

假设:

>>> print(txt)
Josh123: Level 2
Marcus N: Level 4
Callie [L16]: Level 1
Ashley 4: Level 3

你可以这样做:

>>> sorted(txt.splitlines(), key=lambda line: -int(line.split()[-1]))
['Marcus N: Level 4', 'Ashley 4: Level 3', 'Josh123: Level 2', 'Callie [L16]: Level 1']

答案 5 :(得分:0)

你可以尝试类似的东西:

map_data={}
with open('file.txt','r') as f:
    for line in f:
        map_data[line.split(':')[1].strip().split()[1]]=line.strip()

print(list(map(lambda x:map_data[x],sorted(map_data,reverse=True))))

输出:

['Marcus N: Level 4', 'Ashley 4: Level 3', 'Josh123: Level 2', 'Callie [L16]: Level 1']