Не алфавитном порядке список операционной системы.listdir()

Я часто использую python для обработки каталогов данных. Недавно я заметил, что порядок списков по умолчанию изменился на что-то почти бессмысленное. Например, если я нахожусь в текущем каталоге, содержащем следующие подкаталоги: run01, run02,... run19, run20, а затем я создаю список из следующей команды:

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

тогда я обычно получаю список в следующем порядке:

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

и так далее. Раньше порядок был буквенно-цифровым. Но это новое порядок остался со мной на некоторое время.

что определяет (отображаемый) порядок этих списков?

10 ответов


Я думаю, что порядок связан с тем, как файлы индексируются в вашей файловой системе. Если вы действительно хотите, чтобы он придерживался некоторого порядка, вы всегда можете отсортировать список после получения файлов.


вы можете использовать встроенный sorted функция для сортировки строк, как вы хотите. Основываясь на том, что вы описываете,

sorted(os.listdir(whatever_directory))

кроме того, вы можете использовать .sort метод список:

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

Я думаю, что следует сделать трюк.

отметим, что порядок os.listdir получает имена файлов, вероятно, полностью зависит от вашей файловой системы.


на документация:

os.listdir(путь)

возвращает список содержащие названия записей в каталог, заданный путем. список в произвольном порядке. Это не включить специальные записи ".' и '.. даже если они присутствуют в справочник.

порядок не может быть положен на и является артефактом файловая система.

чтобы отсортировать результат, используйте sorted(os.listdir(path)).


Это, вероятно, просто порядок, что C readdir() возвращает. Попробуйте запустить эту программу с:

#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.

P. S. Только сейчас управлял этой и коде Python, и они оба дали мне отсортированный выходной, поэтому я не могу воспроизвести то, что вы видите.


Python по какой-либо причине не поставляется со встроенным способом иметь естественная сортировка (что означает 1, 2, 10 вместо 1, 10, 2), поэтому вы должны написать его сами:

import re
def sorted_aphanumeric(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_aphanumeric(os.listdir(...))

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.

Я нашел, что "сортировка" не всегда делает то, что я ожидал. например, у меня есть каталог, как показано ниже, и "сортировка" дает мне очень странный результат:

>>> 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']

Кажется, он сначала сравнивает первый символ, если это самый большой, он будет последним.


предлагаемая комбинация os.listdir и отсортированный команды генерируют тот же результат, что и ls-l команда под Linux. Следующий пример подтверждает это предположение:

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, сортировка( os.listdir( реж ) ) работает довольно хорошо.


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]))

Эллиот ответ решает его отлично, но поскольку это комментарий, он остается незамеченным, поэтому с целью помочь кому-то, я повторяю его как решение.

использовать библиотеку natsort:

установите библиотеку со следующей командой для Ubuntu и других версий Debian

Python 2

sudo pip install natsort

Python 3

sudo pip3 install natsort

информация о том, как использовать эту библиотеку найдено здесь