166

我经常使用 python 来处理数据目录。最近,我注意到列表的默认顺序已更改为几乎荒谬的东西。例如,如果我在包含以下子目录的当前目录中:run01、run02、... run19、run20,然后我从以下命令生成一个列表:

dir = os.listdir(os.getcwd())

然后我通常会按以下顺序得到一个列表:

dir = ['run01', 'run18', 'run14', 'run13', 'run12', 'run11', 'run08', ... ]

等等。该顺序曾经是字母数字的。但是这个新秩序已经存在了一段时间了。

是什么决定了这些列表的(显示)顺序?

4

14 回答 14

190

您可以根据需要使用内置sorted函数对字符串进行排序。根据你的描述,

sorted(os.listdir(whatever_directory))

或者,您可以使用.sort列表的方法:

lst = os.listdir(whatever_directory)
lst.sort()

我认为应该做的伎俩。

请注意,os.listdir获取文件名的顺序可能完全取决于您的文件系统。

于 2013-02-21T13:35:36.980 回答
81

我认为顺序与文件在文件系统上的索引方式有关。如果你真的想让它遵守某种顺序,你总是可以在获取文件后对列表进行排序。

于 2011-01-27T05:41:17.017 回答
53

根据文档

os.listdir(路径)

返回一个列表,其中包含路径给定的目录中条目的名称。该列表是任意顺序的。它不包括特殊条目“。” 和 '..' 即使它们存在于目录中。

订单不能依赖,是文件系统的产物。

要对结果进行排序,请使用sorted(os.listdir(path)).

于 2011-01-27T07:26:22.083 回答
46

无论出于何种原因,Python 都没有内置的自然排序方式(意思是 1、2、10 而不是 1、10、2),所以你必须自己编写:

import re
def sorted_alphanumeric(data):
    convert = lambda text: int(text) if text.isdigit() else text.lower()
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(data, key=alphanum_key)

您现在可以使用此函数对列表进行排序:

dirlist = sorted_alphanumeric(os.listdir(...))

问题: 如果您使用上述函数对字符串(例如文件夹名称)进行排序并希望它们像 Windows 资源管理器那样排序,则在某些边缘情况下将无法正常工作。
如果您的文件夹名称中包含某些“特殊”字符,则此排序功能将在 Windows 上返回不正确的结果。例如,此函数将排序1, !1, !a, a,而 Windows Explorer 将排序!1, 1, !a, a

因此,如果您想像Windows Explorer 在 Python 中一样进行排序,您必须通过 ctypes 使用 Windows 内置函数StrCmpLogicalW(这当然不适用于 Unix):

from ctypes import wintypes, windll
from functools import cmp_to_key

def winsort(data):
    _StrCmpLogicalW = windll.Shlwapi.StrCmpLogicalW
    _StrCmpLogicalW.argtypes = [wintypes.LPWSTR, wintypes.LPWSTR]
    _StrCmpLogicalW.restype  = wintypes.INT

    cmp_fnc = lambda psz1, psz2: _StrCmpLogicalW(psz1, psz2)
    return sorted(data, key=cmp_to_key(cmp_fnc))

此功能比sorted_alphanumeric().

奖励:winsort还可以在 Windows 上对完整路径进行排序

或者,特别是如果您使用 Unix,您可以使用natsort库 ( pip install natsort) 以正确的方式按完整路径排序(意味着正确位置的子文件夹)。

您可以像这样使用它来对完整路径进行排序:

from natsort import natsorted, ns
dirlist = natsorted(dirlist, alg=ns.PATH | ns.IGNORECASE)

从 7.1.0 版开始,natsort 支持os_sorted在内部使用前面提到的 Windows API 或 Linux 排序,应该使用natsorted().

于 2017-12-30T02:07:55.933 回答
21

我认为默认情况下,顺序是由 ASCII 值确定的。这个问题的解决方案是这样的

dir = sorted(os.listdir(os.getcwd()), key=len)
于 2019-07-09T06:24:57.650 回答
7

使用natsort库:

使用以下命令为 Ubuntu 和其他 Debian 版本安装库

蟒蛇2

sudo pip install natsort

蟒蛇 3

sudo pip3 install natsort

有关如何使用此库的详细信息,请参见此处

from natsort import natsorted

files = ['run01', 'run18', 'run14', 'run13', 'run12', 'run11', 'run08']
natsorted(files)

[out]:
['run01', 'run08', 'run11', 'run12', 'run13', 'run14', 'run18']
  • 这不是answer的副本。natsort于 2020 年 1 月 27 日作为编辑添加。
于 2018-08-22T13:36:56.853 回答
5

这可能只是 C 的readdir()返回顺序。尝试运行这个 C 程序:

#include <dirent.h>
#include <stdio.h>

int main(void){
   DIR *dirp;
   struct dirent* de;
   dirp = opendir(".");
   while(de = readdir(dirp)) // Yes, one '='.
        printf("%s\n", de->d_name);
   closedir(dirp);
   return 0;
}

构建线应该类似于gcc -o foo foo.c.

PS 刚刚运行了这个和你的 Python 代码,它们都给了我排序的输出,所以我无法重现你所看到的。

于 2011-01-27T05:46:27.843 回答
5
aaa = ['row_163.pkl', 'row_394.pkl', 'row_679.pkl', 'row_202.pkl', 'row_1449.pkl', 'row_247.pkl', 'row_1353.pkl', 'row_749.pkl', 'row_1293.pkl', 'row_1304.pkl', 'row_78.pkl', 'row_532.pkl', 'row_9.pkl', 'row_1435.pkl']                                                                                                                                                                                                                                                                                                 
sorted(aaa, key=lambda x: int(os.path.splitext(x.split('_')[1])[0]))

因为在我的要求的情况下,我有像row_163.pkl这里这样的情况os.path.splitext('row_163.pkl')将它分解成('row_163', '.pkl')所以也需要根据'_'来分割它。

但如果您有要求,您可以执行类似的操作

sorted(aa, key = lambda x: (int(re.sub('\D','',x)),x))

在哪里

aa = ['run01', 'run08', 'run11', 'run12', 'run13', 'run14', 'run18']

也可以用于目录检索sorted(os.listdir(path))

对于喜欢的情况,'run01.txt'或者'run01.csv'你可以这样做

sorted(files, key=lambda x : int(os.path.splitext(x)[0]))
于 2017-09-06T12:46:54.883 回答
3

建议的os.listdir和命令组合生成与Linux 下sorted的命令相同的结果。ls -l下面的例子验证了这个假设:

user@user-PC:/tmp/test$ touch 3a 4a 5a b c d1 d2 d3 k l p0 p1 p3 q 410a 409a 408a 407a
user@user-PC:/tmp/test$ ls -l
total 0
-rw-rw-r-- 1 user user 0 Feb  15 10:31 3a
-rw-rw-r-- 1 user user 0 Feb  15 10:31 407a
-rw-rw-r-- 1 user user 0 Feb  15 10:31 408a
-rw-rw-r-- 1 user user 0 Feb  15 10:31 409a
-rw-rw-r-- 1 user user 0 Feb  15 10:31 410a
-rw-rw-r-- 1 user user 0 Feb  15 10:31 4a
-rw-rw-r-- 1 user user 0 Feb  15 10:31 5a
-rw-rw-r-- 1 user user 0 Feb  15 10:31 b
-rw-rw-r-- 1 user user 0 Feb  15 10:31 c
-rw-rw-r-- 1 user user 0 Feb  15 10:31 d1
-rw-rw-r-- 1 user user 0 Feb  15 10:31 d2
-rw-rw-r-- 1 user user 0 Feb  15 10:31 d3
-rw-rw-r-- 1 user user 0 Feb  15 10:31 k
-rw-rw-r-- 1 user user 0 Feb  15 10:31 l
-rw-rw-r-- 1 user user 0 Feb  15 10:31 p0
-rw-rw-r-- 1 user user 0 Feb  15 10:31 p1
-rw-rw-r-- 1 user user 0 Feb  15 10:31 p3
-rw-rw-r-- 1 user user 0 Feb  15 10:31 q

user@user-PC:/tmp/test$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.listdir( './' )
['d3', 'k', 'p1', 'b', '410a', '5a', 'l', 'p0', '407a', '409a', '408a', 'd2', '4a', 'p3', '3a', 'q', 'c', 'd1']
>>> sorted( os.listdir( './' ) )
['3a', '407a', '408a', '409a', '410a', '4a', '5a', 'b', 'c', 'd1', 'd2', 'd3', 'k', 'l', 'p0', 'p1', 'p3', 'q']
>>> exit()
user@user-PC:/tmp/test$ 

因此,对于想要ls -l在他们的 python 代码中重现著名命令的结果的人来说,sorted( os.listdir( DIR ) )效果很好。

于 2017-02-15T08:45:15.890 回答
2

我发现“排序”并不总是符合我的预期。例如,我有一个如下目录,“排序”给了我一个非常奇怪的结果:

>>> os.listdir(pathon)
['2', '3', '4', '5', '403', '404', '407', '408', '410', '411', '412', '413', '414', '415', '416', '472']
>>> sorted([ f for f in os.listdir(pathon)])
['2', '3', '4', '403', '404', '407', '408', '410', '411', '412', '413', '414', '415', '416', '472', '5']

似乎它首先比较第一个字符,如果那是最大的,它将是最后一个。

于 2014-01-29T07:37:29.113 回答
2

文档中:

该列表按任意顺序排列,不包括特殊条目“.”。和 '..' 即使它们存在于目录中。

这意味着该顺序可能取决于操作系统/文件系统,没有特别有意义的顺序,因此不能保证是特别的。正如提到的许多答案:如果愿意,可以对检索到的列表进行排序。

干杯:)

于 2019-10-24T00:36:21.213 回答
0
In [6]: os.listdir?

Type:       builtin_function_or_method
String Form:<built-in function listdir>
Docstring:
listdir(path) -> list_of_strings
Return a list containing the names of the entries in the directory.
path: path of directory to list
The list is in **arbitrary order**.  It does not include the special
entries '.' and '..' even if they are present in the directory.
于 2013-02-21T13:36:54.977 回答
0

ls默认情况下预览按名称排序的文件。(ls选项可用于按日期、大小等排序)

files = list(os.popen("ls"))
files = [file.strip("\n") for file in files]

当目录包含这么多文件时,使用ls会有更好的性能。

于 2021-01-26T10:32:39.170 回答
0

要直接回答问题,可以使用以下代码。

dir = ['run01', 'run18', 'run14', 'run13', 'run12', 'run11', 'run08']
for file in sorted(dir, key=lambda x:int(x.replace('run', ''))):
    print(file)

它将打印:

run01
run08
run11
run12
run13
run14
run18

此方法使用 Python 内置方法sorted,并通过key参数指定排序标准,即不带 'run' 的列表项转换为整数。

于 2022-01-26T14:01:45.133 回答