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

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

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

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

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

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

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



답변

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


답변

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

sorted(os.listdir(whatever_directory))

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

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

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

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


답변

문서 :

os.listdir (경로)

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

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

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


답변

어떤 이유로 든 파이썬에는 자연스러운 정렬 (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().


답변

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

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


답변

아마도 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 코드를 실행했는데 둘 다 나에게 정렬 된 출력을 제공 했으므로보고있는 것을 재현 할 수 없습니다.


답변

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