web-dev-qa-db-fra.com

Ordre de liste non alphanumérique de os.listdir ()

J'utilise souvent python pour traiter les répertoires de données. Récemment, j'ai remarqué que l'ordre par défaut des listes a changé pour devenir quelque chose de presque absurde. Par exemple, si je suis dans un répertoire en cours contenant les sous-répertoires suivants: run01, run02, ... run19, run20, je génère une liste à partir de la commande suivante:

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

alors je reçois habituellement une liste dans cet ordre:

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

etc. Auparavant, l'ordre était alphanumérique. Mais ce nouvel ordre est resté avec moi pendant un certain temps maintenant.

Qu'est-ce qui détermine l'ordre (affiché) de ces listes?

68
marshall.ward

Je pense que l'ordre a à voir avec la façon dont les fichiers sont indexés sur votre système de fichiers . Si vous voulez vraiment le faire respecter un ordre, vous pouvez toujours trier la liste après avoir obtenu les fichiers.

44
Nowayz

Vous pouvez utiliser la fonction sorted intégrée pour trier les chaînes à votre guise. Sur la base de ce que vous décrivez, 

sorted(os.listdir(whatever_directory))

Alternativement, vous pouvez utiliser la méthode .sort d'une liste:

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

Je pense que devrait faire l'affaire.

Notez que l'ordre dans lequel os.listdir obtient les noms de fichiers dépend probablement entièrement de votre système de fichiers.

84
mgilson

Par la documentation :

os.listdir (chemin) 

Retourne une liste contenant les noms des entrées dans le répertoire donné par chemin. La liste est dans un ordre arbitraire. Ce ne est pas inclure les entrées spéciales '.' et '..' même s'ils sont présents dans le annuaire.

L'ordre ne peut pas être invoqué et est un artefact du système de fichiers.

Pour trier le résultat, utilisez sorted(os.listdir(path)).

34
Mark Tolonen

Python pour une raison quelconque n’est pas livré avec un moyen intégré d’avoir un tri naturel (ce qui signifie 1, 2, 10 au lieu de 1, 10, 2), vous devez donc l’écrire vous-même:

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)

Vous pouvez maintenant utiliser cette fonction pour trier une liste:

dirlist = sorted_aphanumeric(os.listdir(...))
7
user136036

C'est probablement juste l'ordre dans lequel le readdir() est retourné. Essayez d’exécuter ce programme 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 ligne de construction devrait être quelque chose comme gcc -o foo foo.c.

P.S. Je viens d'exécuter ceci et votre code Python, et ils m'ont tous les deux donné une sortie triée, je ne peux donc pas reproduire ce que vous voyez.

5
Mike DeSimone

Je pense que par défaut l'ordre est déterminé avec la valeur ASCII. La solution à ce problème est la suivante

dir = sorted(os.listdir(os.getcwd()), key=len)
3
Zied Khlif

J'ai trouvé "sorte" ne fait pas toujours ce que j'attendais. Par exemple, j'ai un répertoire comme ci-dessous, et le "sort" me donne un résultat très étrange:

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

Il semble qu'il compare le premier caractère en premier, si c'est le plus gros, c'est le dernier.

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

Comme dans le cas de mon besoin, j'ai le cas comme row_163.pkl ici os.path.splitext('row_163.pkl') le divisera en ('row_163', '.pkl') donc besoin de le scinder en fonction de '_' également.

mais en cas de besoin, vous pouvez faire quelque chose comme

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

où 

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

et aussi pour récupérer un répertoire, vous pouvez faire sorted(os.listdir(path))

et pour le cas de comme 'run01.txt' ou 'run01.csv' vous pouvez faire comme ceci 

sorted(files, key=lambda x : int(os.path.splitext(x)[0]))
1
rajeshcis
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.
1
Denis

La combinaison proposée de os.listdir et triées commandes génère le même résultat que ls -l commande sous Linux. L'exemple suivant vérifie cette hypothèse:

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$ 

Donc, pour quelqu'un qui veut reproduire le résultat de la commande bien connue ls -l dans son code Python, sort (OS.listdir (DIR)) fonctionne plutôt bien.

0
funk

Elliot answer le résout parfaitement, mais comme c'est un commentaire, il passe inaperçu, alors dans le but d'aider quelqu'un, je le répète comme une solution.

Utiliser la bibliothèque natsort: 

Installez la bibliothèque avec la commande suivante pour Ubuntu et les autres versions de Debian 

Python 2

Sudo pip install natsort

Python 3

Sudo pip3 install natsort

Vous trouverez des détails sur l'utilisation de cette bibliothèque ici

0
rocksyne