python - from - Orden de la lista no alfanumérica de os.listdir()
read all files in directory python (9)
A menudo uso python para procesar directorios de datos. Recientemente, he notado que el orden predeterminado de las listas ha cambiado a algo casi absurdo. Por ejemplo, si estoy en un directorio actual que contiene los siguientes subdirectorios: run01, run02, ... run19, run20, y luego genero una lista del siguiente comando:
dir = os.listdir(os.getcwd())
entonces generalmente obtengo una lista en este orden:
dir = [''run01'', ''run18'', ''run14'', ''run13'', ''run12'', ''run11'', ''run08'', ... ]
y así. El orden solía ser alfanumérico. Pero este nuevo orden ha permanecido conmigo por un tiempo ahora.
¿Qué está determinando el orden (mostrado) de estas listas?
Creo que el orden tiene que ver con la forma en que los archivos están indexados en su FileSystem. Si realmente desea que se adhiera a algún orden, siempre puede ordenar la lista después de obtener los archivos.
Encontré que "ordenar" no siempre hace lo que esperaba. por ejemplo, tengo un directorio como el siguiente, y el "tipo" me da un resultado muy extraño:
>>> 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'']
Parece que compara primero al primer personaje, si ese es el más grande, sería el último.
La combinación propuesta de os.listdir y comandos ordenados genera el mismo resultado que el comando ls -l en Linux. El siguiente ejemplo verifica esta suposición:
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$
Entonces, para alguien que quiera reproducir el resultado del conocido comando ls -l en su código Python, ordenado (os.listdir (DIR)) funciona bastante bien.
Por la documentation :
os.listdir (ruta)
Devuelve una lista que contiene los nombres de las entradas en el directorio indicado por la ruta. La lista está en orden arbitrario . No incluye las entradas especiales ''.'' y ''..'' incluso si están presentes en el directorio.
No se puede confiar en el orden y es un artefacto del sistema de archivos.
Para ordenar el resultado, use sorted(os.listdir(path))
.
Probablemente sea solo el orden que readdir()
C devuelve. Intenta ejecutar este programa 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;
}
La línea de compilación debería ser algo así como gcc -o foo foo.c
PD Simplemente ejecuté esto y tu código de Python, y ambos me dieron una salida ordenada, por lo que no puedo reproducir lo que estás viendo.
Puede usar la función sorted
interna para ordenar las cadenas como lo desee. De acuerdo con lo que describes,
sorted(os.listdir(whatever_directory))
Alternativamente, puede usar el método .sort
de una lista:
lst = os.listdir(whatever_directory)
lst.sort()
Creo que debería hacer el truco.
Tenga en cuenta que el orden en que os.listdir
obtiene los nombres de los archivos es probablemente completamente dependiente de su sistema de archivos.
Python, por el motivo que sea, no viene con una forma incorporada de clasificación natural (es decir, 1, 2, 10 en lugar de 1, 10, 2), por lo que debe escribirlo usted mismo:
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)
Ahora puede usar esta función para ordenar una lista:
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.
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]))
Como en el caso de un requisito mío, tengo el caso como row_163.pkl
aquí os.path.splitext(''row_163.pkl'')
lo (''row_163'', ''.pkl'')
en (''row_163'', ''.pkl'')
así que es necesario dividirlo basado en ''_ '' además.
pero en caso de que lo requiera, puede hacer algo como
sorted(aa, key = lambda x: (int(re.sub(''/D'','''',x)),x))
dónde
aa = [''run01'', ''run08'', ''run11'', ''run12'', ''run13'', ''run14'', ''run18'']
y también para la recuperación de directorio puede hacer sorted(os.listdir(path))
y para el caso de like ''run01.txt''
o ''run01.csv''
puede hacer esto
sorted(files, key=lambda x : int(os.path.splitext(x)[0]))