Python 中简单而灵活的自然排序。
项目描述
Python 中简单而灵活的自然排序。
注意:有关更改,请参阅已弃用的已弃用 API部分。
快速说明
当您尝试对包含数字的字符串列表进行排序时,正常的 python 排序算法会按字典顺序排序,因此您可能不会得到您期望的结果:
>>> 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']
请注意,它的顺序是 ('1', '10', '2') - 这是因为列表是按字典顺序排序的,它对数字的排序就像字母一样(即 'b'、'ba'、' C')。
natsort提供了一个函数natsorted来帮助“自然地”对列表进行排序(“自然地”是相当不明确的,但通常它意味着基于含义而不是计算机代码点的排序)。使用natsorted很简单:
>>> from natsort import natsorted
>>> 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识别字符串中任意位置的数字并自然排序。以下是您可以使用natsort执行的其他一些操作 (另请参阅示例 以获取快速入门指南,或 api以获取完整详细信息)。
注意:natsorted被设计为内置排序功能的替代品。与sorted一样,natsorted 不会就地排序。要对列表进行排序并将输出分配给同一变量,您必须将输出显式分配给变量:
>>> 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']
请参阅生成可重复使用的排序键和就地排序,了解自然就地排序的另一种方法。
快速示例
排序版本
natsort实际上并不理解版本号。碰巧最常见的版本控制方案被设计为与标准的自然排序技术一起工作。这些方案包括 MAJOR.MINOR、MAJOR.MINOR.PATCH、YEAR.MONTH.DAY。如果您的数据符合这样的方案,那么它将使用 natsorted开箱即用(从natsort版本 >= 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']
如果您需要使用更复杂方案的版本,请参阅 这些示例。
像我的文件浏览器一样对路径进行排序(例如 Windows 上的 Windows 资源管理器)
在natsort版本 7.1.0 之前,能够对 Windows 资源管理器等路径进行排序是一个常见的请求。从natsort 7.1.0 开始,添加了函数 os_sorted以使用户能够按照他们的文件浏览器可能排序的顺序进行排序(例如 Windows 上的 Windows Explorer、MacOS 上的 Finder、Linux 上的 Dolphin/Nautilus/Thunar/等) )。
import os
from natsort import os_sorted
print(os_sorted(os.listdir()))
# The directory sorted like your file browser might show
根据您使用的操作系统,输出会有所不同。
对于不在Windows 上的用户(例如 MacOS/Linux),强烈建议也安装PyICU,这将有助于 natsort提供与大多数文件浏览器匹配的结果。如果没有安装它,它将退回到 Python 的内置语言环境模块,并且会为大多数输入提供良好的结果,但会为特殊字符提供较差的结果。
按实数排序(即有符号浮点数)
这在科学数据分析中很有用(并且是natsorted对于natsort 版本 < 4.0.0 的默认行为)。使用realsorted函数:
>>> from natsort import realsorted, 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']
区域感知排序(或“人工排序”)
这是非数字字符也根据它们的含义而不是它们的序数值进行排序的地方,并且在数字中考虑了依赖于语言环境的千位分隔符和小数分隔符。这可以通过humansorted函数来实现:
>>> a = ['Apple', 'apple15', 'Banana', 'apple14,689', 'banana']
>>> natsorted(a)
['Apple', 'Banana', 'apple14,689', 'apple15', 'banana']
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
'en_US.UTF-8'
>>> natsorted(a, alg=ns.LOCALE)
['apple15', 'apple14,689', 'Apple', 'banana', 'Banana']
>>> from natsort import humansorted
>>> humansorted(a) # shortcut for natsorted with alg=ns.LOCALE
['apple15', 'apple14,689', 'Apple', 'banana', 'Banana']
您可能会发现需要显式设置语言环境才能使其正常工作(如示例所示)。在使用humansorted函数之前,请参阅下面的语言环境问题和 可选依赖项部分。
进一步定制 Natsort
如果您需要组合多个算法修饰符(例如ns.REAL、 ns.LOCALE和ns.IGNORECASE),您可以使用按位或运算符 ( | ) 组合选项。例如,
>>> 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.L
True
>>> # 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)
True
所有可用的定制都可以在 ns 枚举的文档中找到。
您还可以使用key参数添加自己的自定义转换函数 。如果您愿意,这些可以与alg一起使用。
>>> a = ['apple2.50', '2.3apple']
>>> natsorted(a, key=lambda x: x.replace('apple', ''), alg=ns.REAL)
['2.3apple', 'apple2.50']
对混合类型进行排序
排序时可以混合和匹配int、float和str(或unicode)类型:
>>> a = ['4.5', 6, 2.0, '5', 'a']
>>> natsorted(a)
[2.0, '4.5', '5', 6, 'a']
>>> # sorted(a) would raise an "unorderable types" TypeError
处理字节
natsort不正式支持bytes类型,但提供了方便的函数来帮助您首先解码为str:
>>> from natsort import as_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']
True
生成可重用排序键并就地排序
在后台,natsorted通过使用natsort_keygen生成自定义排序键,然后将其传递给内置的 sorted 来工作。您可以自己使用natsort_keygen函数生成自定义排序键,以便使用list.sort 方法进行就地排序。
>>> from natsort import natsort_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']
进一步自定义 Natsort部分中提到的所有算法自 定义也可以通过alg关键字选项应用于 natsort_keygen 。
其他有用的东西
常问问题
- 如何调试natsort.natsorted()?
调试natsorted()的最佳方法是使用natsort_keygen()生成密钥 ,并将相同的选项传递给natsorted。可以使用此键查看他们的输入到底做了什么 - 强烈建议查看描述如何调试 的问题以了解如何调试,并查看 Natsort 如何工作?natsort为何 对您的数据执行此操作的 页面。
如果您尝试对自定义类进行排序并遇到麻烦,请查看https://github.com/SethMMorton/natsort/issues/60。简而言之,如果一个依赖于__lt__的行为和自定义类中其他丰富的比较运算符的行为,自定义类不太可能被正确排序 - 最好使用带有natsort的键函数 ,或者使用natsort键作为您丰富的比较运算符定义。
- natsort给了我没想到的结果,这是一个糟糕的库!
您是否尝试使用上述建议进行调试?如果是这样,并且您仍然无法找出错误,那么请提出问题。
- natsort是 如何工作的?
如果您不想阅读Natsort 如何工作?,这是一个快速入门。
natsort提供了一个键函数 ,可以传递给list.sort() 或sorted()以修改默认排序行为。该密钥是使用密钥生成器natsort.natsort_keygen()按需生成的。 natsort.natsorted() 本质上是以下代码的包装器:
>>> from natsort import natsort_keygen >>> natsort_key = natsort_keygen() >>> sorted(['1', '10', '2'], key=natsort_key) ['1', '2', '10']
用户可以使用键 和/或alg选项进一步自定义natsort排序行为(请参阅进一步自定义 Natsort 部分中的详细信息)。
natsort_keygen 生成的键总是返回一个元组。它通过以下方式执行此操作(为清楚起见,省略了一些细节):
假设输入是一个字符串,并尝试使用正则表达式将其拆分为数字和非数字。然后将数字转换为int或float。
如果由于输入不是字符串而导致上述操作失败,则假设输入是其他序列(例如list或tuple),并递归地将键应用于序列的每个元素。
如果由于输入不可迭代而导致上述操作失败,则假设输入是int或float,并在tuple中返回输入。
因为总是返回一个元组,所以TypeError不应该是常见的,除非尝试做一些奇怪的事情,比如对一个list进行排序。
外壳脚本
natsort带有一个名为natsort的 shell 脚本,或者也可以使用python -m natsort 从命令行调用。
要求
natsort需要 Python 3.6 或更高版本。
可选依赖项
快速号码
如果您安装 fastnumbers包(版本 >=2.0.0),则可以进行最有效的排序;它有助于字符串到数字的转换。 natsort在没有包的情况下仍然会(有效地)运行,但是如果您需要挤出多余的汁液,建议您将其作为依赖项包含在内。natsort不会要求(或检查) 安装时是否安装了fastnumbers 。
重症监护室
如果您希望以依赖于区域设置的方式进行排序, 建议您安装PyICU ,请参阅https://natsort.readthedocs.io/en/master/locale_issues.html了解原因。
安装
使用点子!
$ pip install natsort
如果要安装可选依赖项,则可以在安装时使用 “附加”表示法 来安装这些依赖项——fastnumbers使用fast, PyICU使用icu。
# Install both optional dependencies.
$ pip install natsort[fast,icu]
# Install just fastnumbers
$ pip install natsort[fast]
如何运行测试
请注意,natsort未设置为支持python setup.py test。
运行测试的推荐方法是使用tox。安装tox后,运行测试就像在natsort目录中执行以下命令一样简单:
$ tox
tox将为您的测试创建一个虚拟的虚拟环境,并为您安装所有需要的测试要求。您可以使用-e标志指定特定的 python 版本,例如tox -e py36。静态分析是使用tox -e flake8完成的。您可以使用tox --listenvs查看所有可用的测试环境。
如何构建文档
如果要构建natsort的文档,建议使用tox:
$ tox -e docs
这会将文档放在build/sphinx/html中。
已弃用的 API
在natsort版本 6.0.0 中,删除了以下 API 和函数
number_type关键字参数(自 3.4.0 起已弃用)
带符号的关键字参数(自 3.4.0 起已弃用)
exp关键字参数(自 3.4.0 起已弃用)
as_path关键字参数(自 3.4.0 起已弃用)
py3_safe关键字参数(自 3.4.0 起已弃用)
ns.TYPESAFE(自 5.0.0 版起已弃用)
ns.DIGIT(自 5.0.0 版起已弃用)
ns.VERSION(自 5.0.0 版起已弃用)
versorted()(自 4.0.0 版起不鼓励使用,自 5.5.0 版起正式弃用)
index_versorted()(自 4.0.0 版起不鼓励使用,自 5.5.0 版起正式弃用)
一般来说,如果您想确定您是否使用过时的 API,您可以使用以下标志运行您的代码
$ python -Wdefault::DeprecationWarning my-code.py
默认情况下不显示DeprecationWarnings,但这将导致它们被显示。或者,您可以将环境变量 PYTHONWARNINGS设置为“default::DeprecationWarning”,然后运行您的代码。