[python] 문자열 자연 정렬을위한 내장 함수가 있습니까?

Python 3.x를 사용하면 자연스러운 알파벳 정렬을 수행하려는 문자열 목록이 있습니다.

자연 정렬 : Windows의 파일이 정렬되는 순서입니다.

예를 들어 다음 목록은 자연스럽게 정렬됩니다 (원하는 것).

['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']

그리고 여기 위 목록의 “정렬 된”버전이 있습니다 :

['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']

첫 번째 기능처럼 작동하는 정렬 기능을 찾고 있습니다.



답변

PyPI에는 natsort 라는 타사 라이브러리가 있습니다 (전체 공개, 저는 패키지 작성자입니다). 귀하의 경우 다음 중 하나를 수행 할 수 있습니다.

>>> from natsort import natsorted, ns
>>> x = ['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']
>>> natsorted(x, key=lambda y: y.lower())
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
>>> natsorted(x, alg=ns.IGNORECASE)  # or alg=ns.IC
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']

natsort일반적인 알고리즘 을 사용하므로 입력하는 거의 모든 입력에 대해 작동해야합니다. 자신의 기능을 롤링하는 대신 라이브러리를 선택하는 이유에 대한 자세한 내용을 보려면 natsort설명서의 작동 방식 페이지, 특히 특별 사례를 확인하십시오! 부분.


정렬 함수 대신 정렬 키가 필요한 경우 아래 수식 중 하나를 사용하십시오.

>>> from natsort import natsort_keygen, ns
>>> l1 = ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
>>> l2 = l1[:]
>>> natsort_key1 = natsort_keygen(key=lambda y: y.lower())
>>> l1.sort(key=natsort_key1)
>>> l1
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
>>> natsort_key2 = natsort_keygen(alg=ns.IGNORECASE)
>>> l2.sort(key=natsort_key2)
>>> l2
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']


답변

이 시도:

import re

def natural_sort(l):
    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(l, key = alphanum_key)

산출:

['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']

여기에서 적용된 코드 : 인간을위한 정렬 : 자연 정렬 순서 .


답변

Mark Byer의 답변은 훨씬 더 파이썬 버전입니다.

import re

def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
    return [int(text) if text.isdigit() else text.lower()
            for text in _nsre.split(s)]    

이제이 기능을 사용하는 기능, 등의 키로서 사용할 수있다 list.sort, sorted, max

람다로서 :

lambda s: [int(t) if t.isdigit() else t.lower() for t in re.split('(\d+)', s)]


답변

http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html 을 기반으로 함수를 작성하여 여전히 자신의 ‘키’매개 변수를 전달하는 기능을 추가했습니다. 문자열뿐만 아니라 더 복잡한 객체를 포함하는 자연스러운 종류의 목록을 수행하려면 이것이 필요합니다.

import re

def natural_sort(list, key=lambda s:s):
    """
    Sort the list into natural alphanumeric order.
    """
    def get_alphanum_key_func(key):
        convert = lambda text: int(text) if text.isdigit() else text
        return lambda s: [convert(c) for c in re.split('([0-9]+)', key(s))]
    sort_key = get_alphanum_key_func(key)
    list.sort(key=sort_key)

예를 들면 다음과 같습니다.

my_list = [{'name':'b'}, {'name':'10'}, {'name':'a'}, {'name':'1'}, {'name':'9'}]
natural_sort(my_list, key=lambda x: x['name'])
print my_list
[{'name': '1'}, {'name': '9'}, {'name': '10'}, {'name': 'a'}, {'name': 'b'}]


답변

data = ['elm13', 'elm9', 'elm0', 'elm1', 'Elm11', 'Elm2', 'elm10']

데이터를 분석해 봅시다. 모든 요소의 자릿수 용량은 2입니다. 그리고 일반적인 리터럴 부분에는 3 개의 글자가 'elm'있습니다.

따라서 요소의 최대 길이는 5입니다.이 값을 늘려서 (예 : 8) 확인할 수 있습니다.

이를 염두에두고 한 줄 솔루션이 있습니다.

data.sort(key=lambda x: '{0:0>8}'.format(x).lower())

정규 표현식과 외부 라이브러리없이!

print(data)

>>> ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'elm13']

설명:

for elm in data:
    print('{0:0>8}'.format(elm).lower())

>>>
0000elm0
0000elm1
0000elm2
0000elm9
000elm10
000elm11
000elm13


답변

주어진:

data=['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']

SergO 솔루션과 유사하게 외부 라이브러리가없는 1- 라이너는 다음과 같습니다.

data.sort(key=lambda x : int(x[3:]))

또는

sorted_data=sorted(data, key=lambda x : int(x[3:]))

설명:

이 솔루션은 정렬주요 기능을 사용하여 정렬 에 사용될 기능을 정의합니다. 모든 데이터 입력 앞에는 ‘elm’이 있다는 것을 알기 때문에 정렬 함수는 세 번째 문자 뒤의 문자열 부분을 정수로 변환합니다 (예 : int (x [3 :])). 데이터의 숫자 부분이 다른 위치에 있으면 함수의이 부분을 변경해야합니다.

건배


답변

그리고 이제 더 * 우아한 (pythonic) 무언가를 위해 -터치

많은 구현이 있으며 일부는 가까이 왔지만 현대 파이썬이 제공하는 우아함을 포착하지 못했습니다.

  • 파이썬 (3.5.1)을 사용하여 테스트
  • 숫자가 중간 문자열 일 때 작동한다는 것을 보여주는 추가 목록이 포함되었습니다.
  • 그러나 테스트하지는 않았지만 목록의 크기가 조정 가능하면 미리 정규식을 컴파일하는 것이 더 효율적이라고 가정합니다
    • 이것이 잘못된 가정이라면 누군가 나를 교정 할 것이라고 확신합니다.

빨리

from re import compile, split
dre = compile(r'(\d+)')
mylist.sort(key=lambda l: [int(s) if s.isdigit() else s.lower() for s in split(dre, l)])

풀 코드

#!/usr/bin/python3
# coding=utf-8
"""
Natural-Sort Test
"""

from re import compile, split

dre = compile(r'(\d+)')
mylist = ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13', 'elm']
mylist2 = ['e0lm', 'e1lm', 'E2lm', 'e9lm', 'e10lm', 'E12lm', 'e13lm', 'elm', 'e01lm']

mylist.sort(key=lambda l: [int(s) if s.isdigit() else s.lower() for s in split(dre, l)])
mylist2.sort(key=lambda l: [int(s) if s.isdigit() else s.lower() for s in split(dre, l)])

print(mylist)
  # ['elm', 'elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
print(mylist2)
  # ['e0lm', 'e1lm', 'e01lm', 'E2lm', 'e9lm', 'e10lm', 'E12lm', 'e13lm', 'elm']

사용시 주의 사항

  • from os.path import split
    • 수입품을 차별화해야합니다

영감 에서