使用lambda函数按两个子字符串对字符串列表进行排序

时间:2017-09-14 20:56:26

标签: python string sorting lambda

所以我有一个类似于此的字符串列表:

list = ['file.t00Z.wrff02.grib2', 'file.t00Z.wrff03.grib2', 'file.t00Z.wrff00.grib2',
        'file.t00Z.wrff05.grib2', 'file.t00Z.wrff04.grib2', 'file.t00Z.wrff01.grib2', 
        'file.t06Z.wrff01.grib2', 'file.t06Z.wrff00.grib2', 'file.t06Z.wrff02.grib2', ...]

我最近问了一个问题here,其中我学习了如何使用lambda函数通过substring对字符串列表进行排序:

list.sort(key=lambda x: x[x.find('wrff'):])

但现在我需要知道是否有办法按两个不同的子串进行排序,几乎就像数据库中的复合主键一样。我想首先按“file.t”后的两位数对文件进行排序,然后按“wrff”后的两位数进行排序。有没有办法可以同时执行这两项操作?

解决方案:我使用了下面用户Moses Koledoye推荐的两元组lambda函数排序,但是在尝试将此排序过程应用于具有不同命名约定的文件名组时遇到了问题。

在我的脚本中,我有3个Python对象,它们从唯一数据目录中获取文件,并形成包含文件的列表(如上所示)。每个对象都使用不同的命名约定来获取文件,每个不同的文件组在其名称中都有不同数量的数字组。

为了在不增加复杂性的情况下处理这个问题,我决定使用用户Jared Gougen建议的 natsort 模块,并且它工作得非常好。

2 个答案:

答案 0 :(得分:4)

您可以使用re.findall选择前两位数字,然后使用它们在2元组中进行排序:

import re

lst = sorted(lst, key=lambda x: tuple(int(i) for i in re.findall('\d+', x)[:2]))
print(lst)
# ['file.t00Z.wrff00.grib2', 'file.t00Z.wrff01.grib2', 'file.t00Z.wrff02.grib2', 
#  'file.t00Z.wrff03.grib2', 'file.t00Z.wrff04.grib2', 'file.t00Z.wrff05.grib2', 
#  'file.t06Z.wrff00.grib2', 'file.t06Z.wrff01.grib2', 'file.t06Z.wrff02.grib2', ...]

这是file.t之后的第一个数字,然后是wrff之后的数字。

答案 1 :(得分:3)

这似乎正在接近正则表达式有用的区域。这是一个解决方案,它捕获您需要的两个数字子序列。

import re

get_indices = lambda s: re.match('^.*?file\.t([0-9]{2}).*?wrff([0-9]{2}).*$', s).groups()
sorted(file_names, key=get_indices)

或者,在这种情况下,我经常尝试naturally sort文件名。在这些情况下,我在库文件中有以下一组函数。

import re

def tryint(s):
    try:
        return int(s)
    except:
        return s

def getchunks(string):
    return [tryint(c) for c in re.split('([0-9]+)', string)]

def sort_naturally(l):
    return sorted(l, key=getchunks)

如果您正在寻找更重要的东西,那么图书馆natsort就会被编写为更加全面的自然排序。