【问题标题】:Sort a list of strings that contain numbers with SI prefixes对包含带有 SI 前缀的数字的字符串列表进行排序
【发布时间】:2020-08-02 10:26:21
【问题描述】:

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

['default.smt',
 'Setup 19k Hz.smt',
 'Setup 1k Hz.smt',
 'Setup 3 Hz.smt',
 'Setup 500 Hz.smt',
 'Setup 55 Hz.smt',
 'Setup 5k Hz.smt',
 'Setup 9k Hz.smt']

其中k 是1000,例如9k 是9000,应该出现在19k 之前,即19000。

所以我需要我的列表看起来像这样:

['default.smt',
 'Setup 3 Hz.smt',
 'Setup 55 Hz.smt',
 'Setup 500 Hz.smt',
 'Setup 1k Hz.smt',
 'Setup 5k Hz.smt',
 'Setup 9k Hz.smt',
 'Setup 19k Hz.smt']

'default.smt' 单元格可以是第一个也可以是最后一个,我不介意。

我该怎么做?

【问题讨论】:

  • 对于这种情况的快速破解,您可以使用sorted(input, key=lambda x:('k' in x, len(x), x)) 之类的东西,但对于更强大的东西,您必须编写更高级的键功能。

标签: python string sorting numbers natural-sort


【解决方案1】:

您可以在自定义键函数中使用正则表达式。在示例中,我使用了一个幼稚的正则表达式,在某些极端情况下会失败,但您可以调整它。

import re

regex = re.compile(r'(\d+)(k)?')

li = ['default.smt',
 'Setup 19k Hz.smt',
 'Setup 1k Hz.smt',
 'Setup 3 Hz.smt',
 'Setup 500 Hz.smt',
 'Setup 55 Hz.smt',
 'Setup 5k Hz.smt',
 'Setup 9k Hz.smt']

def magic(e):
    match = regex.findall(e)
    if not match:
        return -1
    num, k = int(match[0][0]), match[0][1]
    if k:
        return num * 1000
    return num

print(sorted(li, key=magic))

输出

['default.smt',
 'Setup 3 Hz.smt',
 'Setup 55 Hz.smt',
 'Setup 500 Hz.smt',
 'Setup 1k Hz.smt',
 'Setup 5k Hz.smt',
 'Setup 9k Hz.smt',
 'Setup 19k Hz.smt']

【讨论】:

  • 非常感谢!你有没有想过它可能会失败的极端情况的例子?
  • @Alon123 例如,如果一个字符串将包含另一个不应影响排序的数字
【解决方案2】:

这个答案基本上是从the examples section of natsort's documentation 复制/粘贴的。我所做的只是改变细节。

>>> import re
>>> import natsort
>>>
>>> # Define how each unit will be transformed
>>> conversion_mapping = {
...         "k": 1000,     # kilo
...         "M": 1000000,  # mega
...         # Extend suffixes as you need
... }
>>>
>>> # This regular expression searches for numbers and units
>>> all_units = "|".join(conversion_mapping.keys())
>>> float_re = natsort.numeric_regex_chooser(natsort.FLOAT | natsort.SIGNED)
>>> unit_finder = re.compile(r"({})({})".format(float_re, all_units), re.IGNORECASE)
>>>
>>> def unit_replacer(matchobj):
...     """
...     Given a regex match object, return a replacement string where units are modified
...     """
...     number = matchobj.group(1)
...     unit = matchobj.group(2)
...     new_number = float(number) * conversion_mapping[unit]
...     return "{}".format(new_number)
...
>>> # Demo time!
>>> data = ['default.smt',
...  'Setup 19k Hz.smt',
...  'Setup 1k Hz.smt',
...  'Setup 3 Hz.smt',
...  'Setup 500 Hz.smt',
...  'Setup 55 Hz.smt',
...  'Setup 5k Hz.smt',
...  'Setup 9k Hz.smt']
>>> [unit_finder.sub(unit_replacer, x) for x in data]
['default.smt',
 'Setup 19000.0 Hz.smt',
 'Setup 1000.0 Hz.smt',
 'Setup 3 Hz.smt',
 'Setup 500 Hz.smt',
 'Setup 55 Hz.smt',
 'Setup 5000.0 Hz.smt',
 'Setup 9000.0 Hz.smt']
>>>
>>> natsort.natsorted(data, key=lambda x: unit_finder.sub(unit_replacer, x), alg=natsort.LOWERCASEFIRST)
['default.smt',
 'Setup 3 Hz.smt',
 'Setup 55 Hz.smt',
 'Setup 500 Hz.smt',
 'Setup 1k Hz.smt',
 'Setup 5k Hz.smt',
 'Setup 9k Hz.smt',
 'Setup 19k Hz.smt']

这里的好处是,这不仅使用natsort 的强大算法,而且您还可以使用natsort 的浮点正则表达式定义,即is very thorough

完全披露,我是 natsort 作者。

【讨论】:

    【解决方案3】:

    我用replace() 函数做到了。您可以在不导入的情况下制作此代码。这是我的代码:

        def sortList(list):
    
        sortedList = []
        finalList = []
        for elements in list:
            if elements == "default.smt":
                finalList.append(elements)
            else:
                elements = elements.replace("Setup ", "")
                elements = elements.replace("k", "000")
                elements = elements.replace("Hz.smt", "")
                sortedList.append(int(elements))
        sortedList.sort()
        for elements in sortedList:
            elements = str(elements).replace("000", "k")
            finalList.append("Setup " + str(elements) + " Hz.smt")
        return finalList
    
    
    list = ['default.smt',
            'Setup 19k Hz.smt',
            'Setup 1k Hz.smt',
            'Setup 3 Hz.smt',
            'Setup 500 Hz.smt',
            'Setup 55 Hz.smt',
            'Setup 5k Hz.smt',
            'Setup 9k Hz.smt']
    print(sortList(list))
    

    输出如下:

    ['default.smt', 'Setup 3 Hz.smt', 'Setup 55 Hz.smt', 'Setup 500 Hz.smt', 'Setup 1k Hz.smt', 'Setup 5k Hz.smt', 'Setup 9k Hz.smt', 'Setup 19k Hz.smt']
    

    【讨论】:

      猜你喜欢
      • 2021-08-12
      • 1970-01-01
      • 2012-08-07
      • 2021-02-22
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      • 1970-01-01
      相关资源
      最近更新 更多