Package: natsort
Simple yet flexible natural sorting in Python.Source Code:https://github.com/SethMMorton/natsortDownloads:https://pypi.org/project/natsort/Documentation:https://natsort.readthedocs.io/Examples and RecipesHow Does Natsort Work?APIQuick DescriptionQuick ExamplesFAQRequirementsOptional DependenciesInstallationHow to Run TestsHow to Build DocumentationDropped Deprecated APIsHistoryNOTE: Please see theDropped Deprecated APIssection for changes.Quick DescriptionWhen you try to sort a list of strings that contain numbers, the normal python
sort algorithm sorts lexicographically, so you might not get the results that
you expect:>>>a=['2 ft 7 in','1 ft 5 in','10 ft 2 in','2 ft 11 in','7 ft 6 in']>>>sorted(a)['1 ft 5 in', '10 ft 2 in', '2 ft 11 in', '2 ft 7 in', '7 ft 6 in']Notice that it has the order (‘1’, ‘10’, ‘2’) - this is because the list is
being sorted in lexicographical order, which sorts numbers like you would
letters (i.e. ‘b’, ‘ba’, ‘c’).natsortprovides a functionnatsorted()that helps sort lists
“naturally” (“naturally” is rather ill-defined, but in general it means
sorting based on meaning and not computer code point).
Usingnatsorted()is simple:>>>fromnatsortimportnatsorted>>>a=['2 ft 7 in','1 ft 5 in','10 ft 2 in','2 ft 11 in','7 ft 6 in']>>>natsorted(a)['1 ft 5 in', '2 ft 7 in', '2 ft 11 in', '7 ft 6 in', '10 ft 2 in']natsorted()identifies numbers anywhere in a string and sorts them
naturally. Below are some other things you can do withnatsort(also see theExamples and Recipesfor a quick start guide, or theAPIfor complete details).Note:natsorted()is designed to be a drop-in replacement for the
built-insorted()function. Likesorted(),natsorted()does not sort in-place. To sort a list and assign the output to the same
variable, you must explicitly assign the output to a variable:>>>a=['2 ft 7 in','1 ft 5 in','10 ft 2 in','2 ft 11 in','7 ft 6 in']>>>natsorted(a)['1 ft 5 in', '2 ft 7 in', '2 ft 11 in', '7 ft 6 in', '10 ft 2 in']>>>print(a)# 'a' was not sorted; "natsorted" simply returned a sorted list['2 ft 7 in', '1 ft 5 in', '10 ft 2 in', '2 ft 11 in', '7 ft 6 in']>>>a=natsorted(a)# Now 'a' will be sorted because the sorted list was assigned to 'a'>>>print(a)['1 ft 5 in', '2 ft 7 in', '2 ft 11 in', '7 ft 6 in', '10 ft 2 in']Please seeGenerating a Reusable Sorting Key and Sorting In-Placefor
an alternate way to sort in-place naturally.Quick ExamplesSorting VersionsSort Paths Like My File Browser (e.g. Windows Explorer on Windows)Sorting by Real Numbers (i.e. Signed Floats)Locale-Aware Sorting (or “Human Sorting”)Further Customizing NatsortSorting Mixed TypesHandling BytesGenerating a Reusable Sorting Key and Sorting In-PlaceOther Useful ThingsSorting Versionsnatsortdoes not actuallycomprehendversion numbers.
It just so happens that the most common versioning schemes are designed to
work with standard natural sorting techniques; these schemes includeMAJOR.MINOR,MAJOR.MINOR.PATCH,YEAR.MONTH.DAY. If your data
conforms to a scheme like this, then it will work out-of-the-box withnatsorted()(as ofnatsortversion >= 4.0.0):>>>a=['version-1.9','version-2.0','version-1.11','version-1.10']>>>natsorted(a)['version-1.9', 'version-1.10', 'version-1.11', 'version-2.0']If you need to versions that use a more complicated scheme, please seethese version sorting examples.Sort Paths Like My File Browser (e.g. Windows Explorer on Windows)Prior tonatsortversion 7.1.0, it was a common request to be able to
sort paths like Windows Explorer. As ofnatsort7.1.0, the functionos_sorted()has been added to provide users the ability to sort
in the order that their file browser might sort (e.g Windows Explorer on
Windows, Finder on MacOS, Dolphin/Nautilus/Thunar/etc. on Linux).importosfromnatsortimportos_sortedprint(os_sorted(os.listdir()))# The directory sorted like your file browser might showOutput will be different depending on the operating system you are on.For usersnoton Windows (e.g. MacOS/Linux) it isstronglyrecommended
to also installPyICU, which will helpnatsortgive results that match most file browsers. If this is not installed,
it will fall back on Python’s built-inlocalemodule and will give good
results for most input, but will give poor results for special characters.Sorting by Real Numbers (i.e. Signed Floats)This is useful in scientific data analysis (and was the default behavior
ofnatsorted()fornatsortversion < 4.0.0). Use therealsorted()function:>>>fromnatsortimportrealsorted,ns>>># Note that when interpreting as signed floats, the below numbers are>>>#            +5.10,                -3.00,            +5.30,              +2.00>>>a=['position5.10.data','position-3.data','position5.3.data','position2.data']>>>natsorted(a)['position2.data', 'position5.3.data', 'position5.10.data', 'position-3.data']>>>natsorted(a,alg=ns.REAL)['position-3.data', 'position2.data', 'position5.10.data', 'position5.3.data']>>>realsorted(a)# shortcut for natsorted with alg=ns.REAL['position-3.data', 'position2.data', 'position5.10.data', 'position5.3.data']Locale-Aware Sorting (or “Human Sorting”)This is where the non-numeric characters are also ordered based on their
meaning, not on their ordinal value, and a locale-dependent thousands
separator and decimal separator is accounted for in the number.
This can be achieved with thehumansorted()function:>>>a=['Apple','apple15','Banana','apple14,689','banana']>>>natsorted(a)['Apple', 'Banana', 'apple14,689', 'apple15', 'banana']>>>importlocale>>>locale.setlocale(locale.LC_ALL,'en_US.UTF-8')'en_US.UTF-8'>>>natsorted(a,alg=ns.LOCALE)['apple15', 'apple14,689', 'Apple', 'banana', 'Banana']>>>fromnatsortimporthumansorted>>>humansorted(a)# shortcut for natsorted with alg=ns.LOCALE['apple15', 'apple14,689', 'Apple', 'banana', 'Banana']You may find you need to explicitly set the locale to get this to work
(as shown in the example). Please seelocale issuesand theOptional Dependenciessection below before using thehumansorted()function.Further Customizing NatsortIf you need to combine multiple algorithm modifiers (such asns.REAL,ns.LOCALE, andns.IGNORECASE), you can combine the options using the
bitwise OR operator (|). For example,>>>a=['Apple','apple15','Banana','apple14,689','banana']>>>natsorted(a,alg=ns.REAL|ns.LOCALE|ns.IGNORECASE)['Apple', 'apple15', 'apple14,689', 'Banana', 'banana']>>># The ns enum provides long and short forms for each option.>>>ns.LOCALE==ns.LTrue>>># You can also customize the convenience functions, too.>>>natsorted(a,alg=ns.REAL|ns.LOCALE|ns.IGNORECASE)==realsorted(a,alg=ns.L|ns.IC)True>>>natsorted(a,alg=ns.REAL|ns.LOCALE|ns.IGNORECASE)==humansorted(a,alg=ns.R|ns.IC)TrueAll of the available customizations can be found in the documentation forthe ns enum.You can also add your own custom transformation functions with thekeyargument. These can be used withalgif you wish.>>>a=['apple2.50','2.3apple']>>>natsorted(a,key=lambdax:x.replace('apple',''),alg=ns.REAL)['2.3apple', 'apple2.50']Sorting Mixed TypesYou can mix and matchint,float, andstrtypes when you sort:>>>a=['4.5',6,2.0,'5','a']>>>natsorted(a)[2.0, '4.5', '5', 6, 'a']>>># sorted(a) would raise an "unorderable types" TypeErrorHandling Bytesnatsortdoes not officially support thebytestype, but
convenience functions are provided that help you decode tostrfirst:>>>fromnatsortimportas_utf8>>>a=[b'a',14.0,'b']>>># natsorted(a) would raise a TypeError (bytes() < str())>>>natsorted(a,key=as_utf8)==[14.0,b'a','b']True>>>a=[b'a56',b'a5',b'a6',b'a40']>>># natsorted(a) would return the same results as sorted(a)>>>natsorted(a,key=as_utf8)==[b'a5',b'a6',b'a40',b'a56']TrueGenerating a Reusable Sorting Key and Sorting In-PlaceUnder the hood,natsorted()works by generating a custom sorting
key usingnatsort_keygen()and then passes that to the built-insorted(). You can use thenatsort_keygen()function yourself to
generate a custom sorting key to sort in-place using thelist.sort()method.>>>fromnatsortimportnatsort_keygen>>>natsort_key=natsort_keygen()>>>a=['2 ft 7 in','1 ft 5 in','10 ft 2 in','2 ft 11 in','7 ft 6 in']>>>natsorted(a)==sorted(a,key=natsort_key)True>>>a.sort(key=natsort_key)>>>a['1 ft 5 in', '2 ft 7 in', '2 ft 11 in', '7 ft 6 in', '10 ft 2 in']All of the algorithm customizations mentioned in theFurther Customizing Natsortsection can also be applied tonatsort_keygen()through thealgkeyword option.Other Useful Thingsrecursively descend into lists of listsautomatic unicode normalization of input datacontrolling the case-sensitivitysorting file paths correctlyallow custom sorting keysaccounting for unitsFAQHow do I debugnatsorted()?The best way to debugnatsorted()is to generate a key usingnatsort_keygen()with the same options being passed tonatsorted(). One can take a look at
exactly what is being done with their input using this key - it is highly
recommended tolook at this issue describing how to debugforhowto debug,
and also to review theHow Does Natsort Work?page forwhynatsortis
doing that to your data.If you are trying to sort custom classes and running into trouble, please
take a look athttps://github.com/SethMMorton/natsort/issues/60. In short,
custom classes are not likely to be sorted correctly if one relies
on the behavior of__lt__and the other rich comparison operators in
their custom class - it is better to use akeyfunction withnatsort, or use thenatsortkey as part of your rich comparison
operator definition.natsortgave me results I didn’t expect, and it’s a terrible library!Did you try to debug using the above advice? If so, and you still cannot figure out
the error, then pleasefile an issue.Howdoesnatsortwork?If you don’t want to readHow Does Natsort Work?,
here is a quick primer.natsortprovides akey functionthat can be passed tolist.sort()orsorted()in order to modify the default sorting behavior. This key
is generated on-demand with the key generatornatsort_keygen().natsorted()is essentially a wrapper for the following code:>>>fromnatsortimportnatsort_keygen>>>natsort_key=natsort_keygen()>>>sorted(['1','10','2'],key=natsort_key)['1', '2', '10']Users can further customizenatsortsorting behavior with thekeyand/oralgoptions (see details in theFurther Customizing Natsortsection).The key generated bynatsort_keygen()alwaysreturns atuple. It
does so in the following way (some details omitted for clarity):Assume the input is a string, and attempt to split it into numbers and
non-numbers using regular expressions. Numbers are then converted into
eitherintorfloat.If the above fails because the input is not a string, assume the input
is some other sequence (e.g.listortuple), and recursively
apply the key to each element of the sequence.If the above fails because the input is not iterable, assume the input
is anintorfloat, and just return the input in atuple.Because atupleis always returned, aTypeErrorshould not be common
unless one tries to do something odd like sort anintagainst alist.Shell scriptnatsortcomes with a shell script callednatsort, or can also be called
from the command line withpython-mnatsort.  Check out theshell script wiki documentationfor more details.Requirementsnatsortrequires Python 3.7 or greater.Optional DependenciesfastnumbersThe most efficient sorting can occur if you install thefastnumberspackage
(version >=2.0.0); it helps with the string to number conversions.natsortwill still run (efficiently) without the package, but if you need
to squeeze out that extra juice it is recommended you include this as a
dependency.natsortwill not require (or check) thatfastnumbersis installed at installation.PyICUIt is recommended that you installPyICUif you wish to sort in a
locale-dependent manner, see this page onlocale issuesfor an explanation why.InstallationUsepip!$pipinstallnatsortIf you want to install theOptional Dependencies, you can use the“extras” notationat installation time to install those dependencies as
well - usefastforfastnumbersandicuforPyICU.#Installbothoptionaldependencies.$pipinstallnatsort[fast,icu]#Installjustfastnumbers$pipinstallnatsort[fast]How to Run TestsPlease note thatnatsortis NOT set-up to supportpython setup.py test.The recommended way to run tests is withtox. After installingtox,
running tests is as simple as executing the following in thenatsortdirectory:$toxtoxwill create virtual a virtual environment for your tests and install
all the needed testing requirements for you.  You can specify a particular
python version with the-eflag, e.g.tox-epy36. Static analysis
is done withtox-eflake8. You can see all available testing environments
withtox--listenvs.How to Build DocumentationIf you want to build the documentation fornatsort, it is recommended to
usetox:$tox-edocsThis will place the documentation inbuild/sphinx/html.Dropped Deprecated APIsInnatsortversion 6.0.0, the following APIs and functions were removednumber_typekeyword argument (deprecated since 3.4.0)signedkeyword argument (deprecated since 3.4.0)expkeyword argument (deprecated since 3.4.0)as_pathkeyword argument (deprecated since 3.4.0)py3_safekeyword argument (deprecated since 3.4.0)ns.TYPESAFE(deprecated since version 5.0.0)ns.DIGIT(deprecated since version 5.0.0)ns.VERSION(deprecated since version 5.0.0)versorted()(discouraged since version 4.0.0,
officially deprecated since version 5.5.0)index_versorted()(discouraged since version 4.0.0,
officially deprecated since version 5.5.0)In general, if you want to determine if you are using deprecated APIs you
can run your code with the following flag$python-Wdefault::DeprecationWarningmy-code.pyBy defaultDeprecationWarningsare not shown, but this will cause them
to be shown. Alternatively, you can just set the environment variablePYTHONWARNINGSto “default::DeprecationWarning” and then run your code.AuthorSeth M. MortonHistoryPlease visit the changelogon GitHub.