0

I am trying to sort the following 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']

Where k is 1000, so for example 9k is 9000, and should appear before 19k which is 19000.

So I need my list to look like this:

['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']

The 'default.smt' cell can either be first or last, I don't mind about that.

How can I do this?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Alon123
  • 164
  • 3
  • 15
  • Take a look at https://stackoverflow.com/questions/48413706/sort-string-list-by-a-number-in-string/48413734#48413734 – limido Aug 02 '20 at 10:35
  • 1
    For a quick hack for this case only you can use something like `sorted(input, key=lambda x:('k' in x, len(x), x))`, but for something more robust you'd have to write a more advanced key function. – Joachim Isaksson Aug 02 '20 at 10:35

3 Answers3

2

You can use regex inside a custom key function. In the example I used a naive regex that will fail in some edge-cases, but you can adapt it.

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))

Outputs

['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']
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
0

This answer is basically copy/pasted from the examples section of natsort's documentation. All I have done is change the specifics.

>>> 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']

The advantage here is that not only does this use natsort's robust algorithm, but you also get to use natsort's regular expression definition of floats, which is very thorough.

Full disclosure, I am the natsort author.

SethMMorton
  • 45,752
  • 12
  • 65
  • 86
-2

I did it with the replace() function. You can make this code without import. Here is my code:

    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))

The output is the following:

['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']
Wrench56
  • 290
  • 2
  • 14