Python3中列表的自然排序

时间:2019-11-14 16:32:31

标签: python python-3.x list natural-sort

我正在尝试对列表进行排序:

[
    '[fc] EDW Ratio (10 degrees)', 
    ' [fc] EDW Ratio (45 degrees)', 
    ' [fc] EDW Ratio (60 degrees)', 
    ' [fc] EDW Ratio (25 degrees)', 
    ' [fc] EDW Ratio (20 degrees)', 
    ' [fc] EDW Ratio (30 degrees)', 
    ' [fc] EDW Ratio (15 degrees)', 
    ' [fc] EDW output factor (60 degrees)', 
    ' [fc] Quality index'
]

使用接受的答案here的第一部分:

但是列表最终是这样的:

[
    ' [fc] EDW Ratio (15 degrees)', 
    ' [fc] EDW Ratio (20 degrees)', 
    ' [fc] EDW Ratio (25 degrees)', 
    ' [fc] EDW Ratio (30 degrees)', 
    ' [fc] EDW Ratio (45 degrees)', 
    ' [fc] EDW Ratio (60 degrees)', 
    ' [fc] EDW output factor (60 degrees)', 
    ' [fc] Quality index', 
    '[fc] EDW Ratio (10 degrees)'
]

我希望 EDW比率(10度) 在排序后结束于列表的开头(索引位置0)。

这怎么办?

我的代码包括以下内容:

#
# Method to define natural sorting used to sort lists
#
def atoi(text):
    return int(text) if text.isdigit() else text

def natural_keys(text):
    '''
    alist.sort(key=natural_keys) sorts in human order
    http://nedbatchelder.com/blog/200712/human_sorting.html
    (See Toothy's implementation in the comments)
    '''
    return [ atoi(c) for c in re.split(r'(\d+)', text) ]

    .
    .
    .


    tname_list = test_names.split(",") # this outputs the exact first (unsorted) list shown above

    tname_list.sort(key=natural_keys) # use human sorting defined above. This outputs the second list shown above.

5 个答案:

答案 0 :(得分:3)

您的代码是正确的,但是您的数据看起来不正确:所有条目都有一个前导空格,这意味着它们在您至少确定的那个条目“之前”,实际上没有前导空格。

如果数据正常,我建议您修改代码以忽略前导空格(请检查:How do I remove leading whitespace in Python?)。

答案 1 :(得分:0)

您需要修改natural_keys以仅将字符串的数字部分作为int返回。您应该使用int()进行转换,而不要使用atoi()来返回字符的ascii代码。

答案 2 :(得分:0)

如果任何字符串包含多个数字,或者将数字放在字符串的开头或结尾,您将遇到麻烦。这是因为Python无法将intstr相互比较。您的键函数应该以元组或列表的形式返回。

def atoi(text):
    return (int(text), '') if text.isdigit() else (math.nan, text)

math.nan很特殊,因为它的比较绝不会小于实际数字。

答案 3 :(得分:0)

我建议使用natsort(完整披露,我是作者)。您的数据也有些混乱,您需要删除前导空格以标准化所有条目。

from natsort import natsorted
data = [
    '[fc] EDW Ratio (10 degrees)', 
    ' [fc] EDW Ratio (45 degrees)', 
    ' [fc] EDW Ratio (60 degrees)', 
    ' [fc] EDW Ratio (25 degrees)', 
    ' [fc] EDW Ratio (20 degrees)', 
    ' [fc] EDW Ratio (30 degrees)', 
    ' [fc] EDW Ratio (15 degrees)', 
    ' [fc] EDW output factor (60 degrees)', 
    ' [fc] Quality index'
]
data_sorted = natsorted(data, key=lambda x: x.lstrip())

输出

[
 '[fc] EDW Ratio (10 degrees)',
 ' [fc] EDW Ratio (15 degrees)',
 ' [fc] EDW Ratio (20 degrees)',
 ' [fc] EDW Ratio (25 degrees)',
 ' [fc] EDW Ratio (30 degrees)',
 ' [fc] EDW Ratio (45 degrees)',
 ' [fc] EDW Ratio (60 degrees)',
 ' [fc] EDW output factor (60 degrees)',
 ' [fc] Quality index',
]

答案 4 :(得分:0)

import re

def get_numbers(texto):
    return int(re.findall(r'[0-9]+', texto)[0])
        
def sort_list(l):
    dicto = {}
    for i in l:
        dicto[get_numbers(i)] = i
    lista = []
    for i in sorted(list(dicto.keys())):
        lista.append(dicto[i])
    return lista

sort_list(frames)

请注意,它仅适用于第一组数字......“peter123jjj111”将只考虑 123