0

I have a list of dictionaries that I'm trying to sort. This is what I have so far:

output_list = [{'mac': '0123.4567.89ab', 'port': 'Gi1/0/10'},
               {'mac': '0123.4567.89ab', 'port': 'Gi1/0/1'},
               {'mac': '0123.4567.89ab', 'port': 'Gi1/0/5'},
               {'mac': '0123.4567.89ab', 'port': 'Gi1/0/48'},
               {'mac': '0123.4567.89ab', 'port': 'Gi2/0/1'},
               {'mac': '0123.4567.89ab', 'port': 'Gi1/0/6'},
               {'mac': '0123.4567.89ab', 'port': 'Gi2/0/4'},
               {'mac': '0123.4567.89ab', 'port': 'Gi2/0/13'},
               {'mac': '0123.4567.89ab', 'port': 'Gi8/0/9'},
               {'mac': '0123.4567.89ab', 'port': 'Gi8/0/8'},
               {'mac': '0123.4567.89ab', 'port': 'Te1/1/1'}]

mac_list = sorted(output_list, key=lambda d: "/".join([x for x in d['port'].split("/")]))

pprint(mac_list)

However, it's not sorting the dictionaries the way I want.

"C:\Program Files\Python310\python.exe" "C:/Scripts/Python/test1.py"
[{'mac': '0123.4567.89ab', 'port': 'Gi1/0/1'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/10'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/48'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/5'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/6'},
 {'mac': '0123.4567.89ab', 'port': 'Gi2/0/1'},
 {'mac': '0123.4567.89ab', 'port': 'Gi2/0/13'},
 {'mac': '0123.4567.89ab', 'port': 'Gi2/0/4'},
 {'mac': '0123.4567.89ab', 'port': 'Gi8/0/8'},
 {'mac': '0123.4567.89ab', 'port': 'Gi8/0/9'},
 {'mac': '0123.4567.89ab', 'port': 'Te1/1/1'}]

Process finished with exit code 0

How can I get it to sort it so it looks like this:

[{'mac': '0123.4567.89ab', 'port': 'Gi1/0/1'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/5'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/6'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/10'},
 {'mac': '0123.4567.89ab', 'port': 'Gi1/0/48'},
 {'mac': '0123.4567.89ab', 'port': 'Gi2/0/1'},
 {'mac': '0123.4567.89ab', 'port': 'Gi2/0/4'},
 {'mac': '0123.4567.89ab', 'port': 'Gi2/0/13'},
 {'mac': '0123.4567.89ab', 'port': 'Gi8/0/8'},
 {'mac': '0123.4567.89ab', 'port': 'Gi8/0/9'},
 {'mac': '0123.4567.89ab', 'port': 'Te1/1/1'}]
martineau
  • 119,623
  • 25
  • 170
  • 301
Ryan Bell
  • 169
  • 1
  • 8
  • See [Sorting HOW TO](https://docs.python.org/3/howto/sorting.html) in the documentation. – martineau Jun 22 '22 at 22:58
  • Your calculated port key is still being compare lexicographically, not numerically. Convert it into a tuple and make the numeric portions of it integers. – martineau Jun 22 '22 at 23:04

3 Answers3

1

Try:

out = sorted(
    output_list,
    key=lambda d: (d["port"][:2], *map(int, d["port"][2:].split("/"))),
)

print(out)

Prints:

[
    {"mac": "0123.4567.89ab", "port": "Gi1/0/1"},
    {"mac": "0123.4567.89ab", "port": "Gi1/0/5"},
    {"mac": "0123.4567.89ab", "port": "Gi1/0/6"},
    {"mac": "0123.4567.89ab", "port": "Gi1/0/10"},
    {"mac": "0123.4567.89ab", "port": "Gi1/0/48"},
    {"mac": "0123.4567.89ab", "port": "Gi2/0/1"},
    {"mac": "0123.4567.89ab", "port": "Gi2/0/4"},
    {"mac": "0123.4567.89ab", "port": "Gi2/0/13"},
    {"mac": "0123.4567.89ab", "port": "Gi8/0/8"},
    {"mac": "0123.4567.89ab", "port": "Gi8/0/9"},
    {"mac": "0123.4567.89ab", "port": "Te1/1/1"},
]

Note:

(d["port"][:2], *map(int, d["port"][2:].split("/"))) will create tuple in form ('Gi', 1, 0, 48) etc. The sorted() function will then sort according these tuples.

Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • 1
    While this code may answer the question, it would be better to include some context, explaining _how_ it works and _when_ to use it. Code-only answers are not useful in the long run. – martineau Jun 22 '22 at 23:00
1

Try this:

mac_list = sorted(output_list, key=lambda d: tuple(int(x) if x.isdigit() else x for x in d['port'].split("/")))

This will convert numeric strings to int values in the substrings of the port value produced by split() and leave non-numeric strings as is, and sorting based on the resulting tuple values will get you the desired output.

constantstranger
  • 9,176
  • 2
  • 5
  • 19
1

Seems that you're looking for human/natural sorting. This answer covers it well.

Using the natural_keys function from that answer, the port string could then be passed directly to the defined function as follow:

output_list.sort(key=lambda d: natural_keys(d["port"]))

Acediatic
  • 36
  • 4