SethMMorton / natsort

Simple yet flexible natural sorting in Python.
https://pypi.org/project/natsort/
MIT License
907 stars 52 forks source link

`cmp_to_key` gives an error and I don't know if this is a bug or just not supported #168

Closed secarica closed 11 months ago

secarica commented 11 months ago

I want to adapt an IP address sorter from GeeksforGeeks - Sort the given IP addresses in ascending order and it gives an error related to cmp_to_key.

Attached is a test code, which on my system (Windows 10) gives this error:

""" C:\temp>python testcase_natsorted_ip_sort.py Traceback (most recent call last): File "C:\temp\testcase_natsorted_ip_sort.py", line 57, in ip_list_sorted = sortIPAddress(ip_list) ^^^^^^^^^^^^^^^^^^^^^^ File "C:\temp\testcase_natsorted_ip_sort.py", line 39, in sortIPAddress ip_list_sorted = natsorted(ip_list, key = cmp_to_key(customComparator)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\python31.164\Lib\site-packages\natsort\natsort.py", line 293, in natsorted return sorted(seq, reverse=reverse, key=natsort_keygen(key, alg)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\python31.164\Lib\site-packages\natsort\utils.py", line 350, in natsort_key return num_func(val) ^^^^^^^^^^^^^ File "C:\python31.164\Lib\site-packages\natsort\utils.py", line 433, in func elif val == _nan_replace: ^^^^^^^^^^^^^^^^^^^ TypeError: other argument must be K instance """

By changing back the natsorted with the original sorted, the code then runs fine.

Is this a bug related to natsorted or I have to find another way to get the key ?

SethMMorton commented 11 months ago

This isn't really supported. natsort works by transforming your input into something that can be sorted naturally, then passing that to the key argument to sorted. When you pass a key to natsort, it assumes that the output of that key is something that natsort can handle.

cmp_to_key returns an object that wraps your cmp function to make it behave like a key. natsort cannot transform this object into something useful, and so you get the weird error you see.

SethMMorton commented 11 months ago

I took a look at the link you provided, and that cmp function they define is the same as giving lambda x: x.split(".") as the key (e.g. sorted(arr, key=lambda x: x.split(".")) or natsorted(arr, key=lambda x: x.split(".")). That's the reason Python removed native support for cmp functions in favor of key - you can often express what you are trying to do WAY simpler with a key than with cmp.

Having said that, you should be able to pass those IP addresses to natsort directly and not need a key at all, and it will work as expected.

secarica commented 11 months ago

Tested -- it works fine with lambda etc. de-compactized version so to say, but I will try also a more direct approach.

Thank you very much -- both for the tip and mostly for natsorted :)