web-dev-qa-db-ja.com

os.listdir()からの非英数字リスト順

私は頻繁にpythonを使用してデータのディレクトリを処理します。最近、リストのデフォルトの順序がほとんど意味のないものに変更されていることに気付きました。たとえば、次のサブディレクトリ:run01、run02、... run19、run20、次に次のコマンドからリストを生成します。

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

その後、私は通常、この順序でリストを取得します:

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

等々。順序は英数字でした。しかし、この新しい注文はしばらくの間私に残っています。

これらのリストの(表示される)順序を決定するものは何ですか?

85
marshall.ward

この順序は、FileSystemでのファイルのインデックス方法に関係していると思います。何らかの順序に忠実にしたい場合は、ファイルを取得した後、いつでもリストをソートできます。

50
Nowayz

組み込みのsorted関数を使用して、必要に応じて文字列を並べ替えることができます。説明内容に基づいて、

sorted(os.listdir(whatever_directory))

または、リストの.sortメソッドを使用できます。

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

私はトリックを行うべきだと思います。

os.listdirがファイル名を取得する順序は、おそらくファイルシステムに完全に依存していることに注意してください。

100
mgilson

ドキュメント

os.listdir(パス)

Pathで指定されたディレクトリ内のエントリの名前を含むリストを返します。 リストは任意の順序です。特別なエントリ「。」は含まれません。および「..」がディレクトリに存在する場合でも。

順序は信頼できず、ファイルシステムのアーティファクトです。

結果をソートするには、sorted(os.listdir(path))を使用します。

39
Mark Tolonen

Pythonには、何らかの理由で自然な並べ替え(1、10、2の代わりに1、2、10を意味する)が組み込まれている方法がないため、自分で記述する必要があります。

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(...))
15
user136036

おそらく、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のようなものでなければなりません。

追伸これとあなたのPythonコードを実行しただけで、両方とも私にソートされた出力を与えたので、あなたが見ているものを再現することはできません。

5
Mike DeSimone

デフォルトでは、順序はASCII値で決定されます。この問題の解決策はこれです

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

「ソート」が常に期待したことをするわけではないことがわかりました。たとえば、次のようなディレクトリがあり、「ソート」によって非常に奇妙な結果が得られます。

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

最初の文字を最初に比較し、それが最大の場合は最後の文字になります。

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

私の要件の場合、_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]))
_
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

os.listdirおよびsortedコマンドの提案された組み合わせは、Linuxで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))はかなりうまくいきます。

0
funk

Elliot's answerは完全に解決しますが、コメントであるため気付かれないため、誰かを助ける目的で、解決策として繰り返します。

natsortライブラリを使用:

Ubuntuおよび他のDebianバージョンの場合、次のコマンドでライブラリをインストールします

Python 2

Sudo pip install natsort

Python 3

Sudo pip3 install natsort

このライブラリの使用方法の詳細は here にあります。

0
rocksyne