os.listdir ()에서 영숫자가 아닌 목록 순서


109

나는 종종 파이썬을 사용하여 데이터 디렉토리를 처리합니다. 최근에 나는 목록의 기본 순서가 거의 무의미한 것으로 변경되었음을 발견했습니다. 예를 들어, run01, run02, ... run19, run20 하위 디렉토리가 포함 된 현재 디렉토리에있는 경우 다음 명령에서 목록을 생성합니다.

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

그런 다음 일반적으로 다음 순서로 목록을 얻습니다.

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

등등. 순서는 영숫자였습니다. 그러나이 새로운 질서는 잠시 동안 저에게 남아 있습니다.

이 목록의 (표시) 순서를 결정하는 것은 무엇입니까?


파이썬 목록 내에서의 순서는 실제로 관련이 있습니다 (즉, 목록이 정렬 됨). 나는 Nowayz에 동의합니다 : 당신이보고있는 이상한 순서는 아마도 파일 시스템의 기능 일 것입니다. 나는 이것이 맥에 연결된 타사 네트워크 파일 시스템에서 몇 년 전에 발생하는 것을 보았습니다.
David P Simons 2011 년

정보 감사합니다. 목록 주문 댓글을 삭제했습니다.
marshall.ward

@ shog9 좋아, 이제 질문이 있고 답변이 어떤 종류인지 알 수 있지만 (연결된 답변에 데이터 정렬 방법이 제공되지 않았습니다) 질문 주제가 명확하지 않았습니다 (답이 나타나지 않는 검색 수행) 태그는별로 도움이되지 않았습니다.
Dimitris

@Dimitris : 그것은 공정한 비판입니다. 저는이 질문의 제목을 바꾸고 두 질문을 합쳤으므로 이제 두 가지 답변을 모두 여기서 찾을 수 있으며 귀하의 답변은 여전히 ​​그것을 가리키고 있습니다.
Shog9 2013 년

BTW 다른 사람이 내가 여기에 대한 답변에 대해 혼란스러워한다면 내 질문이 정렬 된 listdir출력을 요청하는 다른 질문과 병합 되었기 때문 입니다. 질문이 병합 된 이유를 잘 모르겠습니다.
marshall.ward

답변:


63

순서는 파일이 파일 시스템에서 색인화되는 방식과 관련이 있다고 생각합니다. 정말로 어떤 순서를 따르고 싶다면 파일을 가져온 후 항상 목록을 정렬 할 수 있습니다.


128

내장 sorted함수를 사용하여 원하는대로 문자열을 정렬 할 수 있습니다 . 설명하신 내용에 따라

sorted(os.listdir(whatever_directory))

또는 .sort목록 방법을 사용할 수 있습니다 .

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

트릭을해야한다고 생각합니다.

os.listdir파일 이름 을 얻는 순서 는 아마도 파일 시스템에 따라 완전히 달라집니다.


1
번호 우선 파일 이름을 처리하는 경우 순서를 변경하지 않습니다 (예 : 59.9780radps-0096이 여전히 9.9746radps-0082 이전 임). 모든 것이 문자열이기 때문에 소수가 제대로 처리되지 않는 것 같습니다.
Elliot

2
또는 방금 찾은 natsort 라이브러리를 사용하십시오.
Elliot

5
나만을 sorted(listdir)위해 일했습니다. listdir.sort()내게 준 : TypeError : 'NoneType'개체는 반복 할 수 없습니다
paul_h

1
@AlexB-물론 ... reverse=True내림차순 정렬로 전달하십시오 .
mgilson

1
@ user3895596- sorted처음 작성된 것이 한 줄로 작성 되었다고 생각합니다 .
mgilson

43

문서 :

os.listdir (경로)

경로로 지정된 디렉토리의 항목 이름이 포함 된 목록을 반환합니다. 목록은 임의의 순서로되어 있습니다. 특수 항목 '.'은 포함되지 않습니다. 및 '..'이 디렉토리에있는 경우에도 마찬가지입니다.

순서는 신뢰할 수 없으며 파일 시스템의 아티팩트입니다.

결과를 정렬하려면을 사용하십시오 sorted(os.listdir(path)).


27

어떤 이유로 든 파이썬에는 자연스러운 정렬 (1, 10, 2 대신 1, 2, 10을 의미 함) 을 갖는 기본 제공 방식이 없으므로 직접 작성해야합니다.

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에서 잘못된 결과를 반환합니다. 예를 들어이 함수는 sort 1, !1, !a, a를 수행하지만 Windows 탐색기는 정렬합니다.!1, 1, !a, a 됩니다.

따라서 Python에서 Windows 탐색기와 똑같이 정렬하려면 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() .

보너스 : Windows에서 전체 경로를 정렬winsort 할 수도 있습니다 . .

또는 특히 Unix를 사용하는 경우 natsort라이브러리 ( pip install natsort)를 사용하여 올바른 방법 (올바른 위치에있는 하위 폴더를 의미)으로 전체 경로를 기준으로 정렬 할 수 있습니다 .

다음과 같이 전체 경로를 정렬 할 수 있습니다.

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

sorted_alphanumeric()위의 기능 보다 상당히 느리기 때문에 폴더 이름 (또는 일반적으로 문자열)의 일반적인 정렬에는 사용하지 마십시오 . Windows 탐색기 정렬을 예상
natsorted하면 라이브러리가 잘못된 결과 를 제공 하므로이를 사용하십시오 winsort().


완벽하게 잘 작동합니다. print( sorted_aphanumeric(["1", "10", "2", "foo_10", "foo_8"]) )-> ['1', '2', '10', 'foo_8', 'foo_10']. 예상대로 정확히.
user136036

natsortedWindows 탐색기와 일치하는 기능을 구현하는 데는 오랫동안 열려있는 문제가 있습니다. 솔루션에 기여해야할까요? github.com/SethMMorton/natsort/issues/41
SethMMorton

8

기본적으로 순서는 ASCII 값으로 결정됩니다. 이 문제에 대한 해결책은 다음과 같습니다.

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

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 .

추신 : 방금이 코드와 Python 코드를 실행했는데 둘 다 나에게 정렬 된 출력을 제공 했으므로보고있는 것을 재현 할 수 없습니다.


1
당신 soted 출력을보고있는 것은 같은 OS, 파일 시스템, 파일의 생성 시간과 같은 요인의 많은에 의존하는 이유, 마지막 조각 모음 동안 행동, ...
요아킴 사우어

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

여기에 틀림없이 최고의 답변이 있습니다.
Amit Amola

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

첫 번째 문자를 먼저 비교하는 것 같습니다. 그것이 가장 큰 경우 마지막 문자가 될 것입니다.


2
이것은 예상 된 동작입니다. ('5' > '403') is True.
AXO

2
이 시점에서 숫자의 양적 값이 아닌 영숫자 정렬을 비교하기 때문에 @AXO가 정확합니다. 예상과 유사한 정렬을 얻으려면 폴더에 숫자 패딩을 사용하는 것이 좋습니다 ... [ '002', '003', '004', '005', '403', '404', ' 405 ','406 ']
Andrew

2

로부터 문서 :

목록은 임의의 순서 이며 특수 항목 '.'을 포함하지 않습니다. 및 '..'이 디렉토리에있는 경우에도 마찬가지입니다.

이는 순서가 아마도 OS / 파일 시스템에 따라 다르며, 특별히 의미있는 순서가 없으므로 특별히 보장되지 않음을 의미합니다. 많은 답변이 언급했듯이 원하는 경우 검색된 목록을 정렬 할 수 있습니다.

건배 :)


2

엘리엇의 대답은 완벽하게 해결되지만 댓글이기 때문에 눈에 띄지 않게되므로 누군가를 돕는 것을 목표로 한 해결책으로 반복하고 있습니다.

natsort 라이브러리 사용 :

Ubuntu 및 기타 Debian 버전에 대해 다음 명령을 사용하여 라이브러리를 설치합니다.

파이썬 2

sudo pip install natsort

파이썬 3

sudo pip3 install natsort

이 라이브러리를 사용하는 방법에 대한 자세한 내용은 여기 에서 찾을 수 있습니다.


1
그것은보다 정확합니다 sorted()! 감사합니다
Färid Alijani 2011

1

제안 된 os.listdirsorted명령어 조합은 ls -lLinux에서 명령어 와 동일한 결과를 생성합니다 . 다음 예제는이 가정을 확인합니다.

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 -lPython 코드에서 잘 알려진 명령 의 결과를 재현하려는 사람에게는 sorted( os.listdir( DIR ) )꽤 잘 작동합니다.


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.

1
이것은 그들이 해결책을 제공하지 않고 행동을 보는 이유를 설명합니다.
Daniel Watkins

1
OP는 방법이 아닌 이유를 알고 싶습니다.
Denis

이 밖을 가리키는 @Denis 감사 - 나는 전에 통보하지 않았다
디미트리

@DanielWatkins OK,이 밤은하지 않음).
데니스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.