복붙노트

[PYTHON] 여러 키로 파이썬 사전 목록 정렬

PYTHON

여러 키로 파이썬 사전 목록 정렬

나는 dicts의 명부가있다 :

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
 {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
 {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
 {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
 {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
 {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
 {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

Total_Points에 의해 역순으로 된 다중 키 정렬을 사용해야하고 TOT_PTS_Misc에 의해 반전되지 않습니다.

명령 프롬프트에서 이렇게 할 수 있습니다 :

a = sorted(b, key=lambda d: (-d['Total_Points'], d['TOT_PTS_Misc']))

그러나 나는 목록과 정렬 키를 전달하는 함수를 통해이를 실행해야합니다. 예를 들어, def multikeysort (dict_list, sortkeys) :.

multikeysort 함수에 넘겨지는 임의의 수의 키에 대해리스트를 정렬하는 람다 라인을 어떻게 사용할 수 있으며, sortkeys가 임의의 수의 키를 가질 수 있고 반전 된 정렬을 필요로하는 것들이 식별 될 것이라는 점을 고려해야합니다 그 전에 '-'로?

해결법

  1. ==============================

    1.이 대답은 사전에있는 모든 종류의 열에 적용됩니다. 부정 된 열은 숫자 일 필요는 없습니다.

    이 대답은 사전에있는 모든 종류의 열에 적용됩니다. 부정 된 열은 숫자 일 필요는 없습니다.

    def multikeysort(items, columns):
        from operator import itemgetter
        comparers = [((itemgetter(col[1:].strip()), -1) if col.startswith('-') else
                      (itemgetter(col.strip()), 1)) for col in columns]
        def comparer(left, right):
            for fn, mult in comparers:
                result = cmp(fn(left), fn(right))
                if result:
                    return mult * result
            else:
                return 0
        return sorted(items, cmp=comparer)
    

    다음과 같이 호출 할 수 있습니다.

    b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]
    
    a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
    for item in a:
        print item
    

    어느 쪽의 열도 무효로 해주세요. 반대로 정렬 순서가 표시됩니다.

    다음 : 여분의 클래스를 사용하지 않도록 변경하십시오.

    2016-01-17

    이 대답에서 영감을 얻으십시오. 반복 가능한 조건에서 첫 번째 항목을 얻는 가장 좋은 방법은 무엇입니까?, 코드 단축 :

    from operator import itemgetter as i
    
    def multikeysort(items, columns):
        comparers = [
            ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
            for col in columns
        ]
        def comparer(left, right):
            comparer_iter = (
                cmp(fn(left), fn(right)) * mult
                for fn, mult in comparers
            )
            return next((result for result in comparer_iter if result), 0)
        return sorted(items, cmp=comparer)
    

    당신의 코드가 간결한 것을 좋아하는 경우에 대비하십시오.

    2016-01-17

    이 작업은 python3 (cmp 인수를 제거하여 정렬)에서 작동합니다.

    from operator import itemgetter as i
    from functools import cmp_to_key
    
    def multikeysort(items, columns):
        comparers = [
            ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
            for col in columns
        ]
        def comparer(left, right):
            comparer_iter = (
                cmp(fn(left), fn(right)) * mult
                for fn, mult in comparers
            )
            return next((result for result in comparer_iter if result), 0)
        return sorted(items, key=cmp_to_key(comparer))
    

    이 대답에서 영감을 얻었습니다 Python 3에서 사용자 정의 정렬을 어떻게해야합니까?

  2. ==============================

    2.이 질문은 다소 오래된 질문이지만, 파이썬은 list.sort ()와 sorted ()와 같은 정렬 루틴에 대해 안정적인 정렬 순서를 보장하지 않는다는 것을 언급하지 않았다. 이는 평등을 비교하는 항목이 원래 순서를 유지한다는 것을 의미한다.

    이 질문은 다소 오래된 질문이지만, 파이썬은 list.sort ()와 sorted ()와 같은 정렬 루틴에 대해 안정적인 정렬 순서를 보장하지 않는다는 것을 언급하지 않았다. 이는 평등을 비교하는 항목이 원래 순서를 유지한다는 것을 의미한다.

    즉, ORDER BY ASC, SQL DESC (SQL 표기법 사용)의 사전 목록을 다음과 같이 수행 할 수 있습니다.

    items.sort(key=operator.itemgetter('age'), reverse=True)
    items.sort(key=operator.itemgetter('name'))
    

    반전 / 반전은 주문할 수있는 모든 유형에 적용됩니다. 빼기 부호를 앞에 붙여서 부인할 수있는 번호가 아닙니다.

    그리고 (적어도) CPython에서 사용 된 Timsort 알고리즘 때문에 실제로는 다소 빠릅니다.

  3. ==============================

    3.

    def sortkeypicker(keynames):
        negate = set()
        for i, k in enumerate(keynames):
            if k[:1] == '-':
                keynames[i] = k[1:]
                negate.add(k[1:])
        def getit(adict):
           composite = [adict[k] for k in keynames]
           for i, (k, v) in enumerate(zip(keynames, composite)):
               if k in negate:
                   composite[i] = -v
           return composite
        return getit
    
    a = sorted(b, key=sortkeypicker(['-Total_Points', 'TOT_PTS_Misc']))
    
  4. ==============================

    4.http://stygianvision.net/updates/python-sort-list-object-dictionary-multiple-key/이 작업을 수행하기위한 다양한 기술에 대한 좋은 개요가 있습니다. 요구 사항이 "전체 양방향 멀티 키"보다 간단하면 한 번 살펴보십시오. 받아 들여지는 대답은 분명하고 블로그 게시물은 나는 어떤 순서로할지 모르지만, 어떤 방식 으로든 서로 영향을 받았다.

    http://stygianvision.net/updates/python-sort-list-object-dictionary-multiple-key/이 작업을 수행하기위한 다양한 기술에 대한 좋은 개요가 있습니다. 요구 사항이 "전체 양방향 멀티 키"보다 간단하면 한 번 살펴보십시오. 받아 들여지는 대답은 분명하고 블로그 게시물은 나는 어떤 순서로할지 모르지만, 어떤 방식 으로든 서로 영향을 받았다.

    링크가 여기에서 죽는 경우 위에서 다루지 않은 예제의 매우 빠른 개요가 있습니다.

    mylist = sorted(mylist, key=itemgetter('name', 'age'))
    mylist = sorted(mylist, key=lambda k: (k['name'].lower(), k['age']))
    mylist = sorted(mylist, key=lambda k: (k['name'].lower(), -k['age']))
    
  5. ==============================

    5.여러 열에서 2 차원 배열을 정렬하기 위해 다음을 사용합니다.

    여러 열에서 2 차원 배열을 정렬하기 위해 다음을 사용합니다.

    def k(a,b):
        def _k(item):
            return (item[a],item[b])
        return _k
    

    이것은 임의의 수의 항목에 대해 작업하도록 확장 될 수 있습니다. 필자는 정렬 가능한 키에 대한 더 나은 액세스 패턴을 찾는 것이 멋진 비교기를 작성하는 것보다 낫다고 생각하는 경향이 있습니다.

    >>> data = [[0,1,2,3,4],[0,2,3,4,5],[1,0,2,3,4]]
    >>> sorted(data, key=k(0,1))
    [[0, 1, 2, 3, 4], [0, 2, 3, 4, 5], [1, 0, 2, 3, 4]]
    >>> sorted(data, key=k(1,0))
    [[1, 0, 2, 3, 4], [0, 1, 2, 3, 4], [0, 2, 3, 4, 5]]
    >>> sorted(a, key=k(2,0))
    [[0, 1, 2, 3, 4], [1, 0, 2, 3, 4], [0, 2, 3, 4, 5]]
    
  6. ==============================

    6.

    from operator import itemgetter
    from functools import partial
    
    def _neg_itemgetter(key, d):
        return -d[key]
    
    def key_getter(key_expr):
        keys = key_expr.split(",")
        getters = []
        for k in keys:
            k = k.strip()
            if k.startswith("-"):
               getters.append(partial(_neg_itemgetter, k[1:]))
            else:
               getters.append(itemgetter(k))
    
        def keyfunc(dct):
            return [kg(dct) for kg in getters]
    
        return keyfunc
    
    def multikeysort(dict_list, sortkeys):
        return sorted(dict_list, key = key_getter(sortkeys)
    

    데모:

    >>> multikeysort([{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 60.0},
                     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0}, 
                     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0}],
                    "-Total_Points,TOT_PTS_Misc")
    [{u'Total_Points': 96.0, u'TOT_PTS_Misc': u'Chappell, Justin'}, 
     {u'Total_Points': 96.0, u'TOT_PTS_Misc': u'Russo, Brandon'}, 
     {u'Total_Points': 60.0, u'TOT_PTS_Misc': u'Utley, Alex'}]
    

    파싱은 약간 깨지기 쉽지만 적어도 키 사이에 공백을 허용합니다.

  7. ==============================

    7.이미 람다 (lambda)에 익숙하기 때문에 좀 덜 장황한 해결책이 있습니다.

    이미 람다 (lambda)에 익숙하기 때문에 좀 덜 장황한 해결책이 있습니다.

    >>> def itemgetter(*names):
        return lambda mapping: tuple(-mapping[name[1:]] if name.startswith('-') else mapping[name] for name in names)
    
    >>> itemgetter('a', '-b')({'a': 1, 'b': 2})
    (1, -2)
    
  8. ==============================

    8.오늘도 비슷한 문제가있었습니다. 숫자 값을 내림차순으로 정렬하고 오름차순으로 문자열 값을 정렬하여 사전 항목을 정렬해야했습니다. 충돌하는 방향의 문제를 해결하기 위해 정수 값을 부정했습니다.

    오늘도 비슷한 문제가있었습니다. 숫자 값을 내림차순으로 정렬하고 오름차순으로 문자열 값을 정렬하여 사전 항목을 정렬해야했습니다. 충돌하는 방향의 문제를 해결하기 위해 정수 값을 부정했습니다.

    여기 내 솔루션의 변형 - OP에 적용 가능

    sorted(b, key=lambda e: (-e['Total_Points'], e['TOT_PTS_Misc']))
    

    아주 간단하고 매력처럼 작동합니다.

    [{'TOT_PTS_Misc': 'Chappell, Justin', 'Total_Points': 96.0},
     {'TOT_PTS_Misc': 'Russo, Brandon', 'Total_Points': 96.0},
     {'TOT_PTS_Misc': 'Utley, Alex', 'Total_Points': 96.0},
     {'TOT_PTS_Misc': 'Foster, Toney', 'Total_Points': 80.0},
     {'TOT_PTS_Misc': 'Lawson, Roman', 'Total_Points': 80.0},
     {'TOT_PTS_Misc': 'Lempke, Sam', 'Total_Points': 80.0},
     {'TOT_PTS_Misc': 'Gnezda, Alex', 'Total_Points': 78.0},
     {'TOT_PTS_Misc': 'Kirks, Damien', 'Total_Points': 78.0},
     {'TOT_PTS_Misc': 'Korecz, Mike', 'Total_Points': 78.0},
     {'TOT_PTS_Misc': 'Worden, Tom', 'Total_Points': 78.0},
     {'TOT_PTS_Misc': 'Burgess, Randy', 'Total_Points': 66.0},
     {'TOT_PTS_Misc': 'Harmon, Gary', 'Total_Points': 66.0},
     {'TOT_PTS_Misc': 'Smugala, Ryan', 'Total_Points': 66.0},
     {'TOT_PTS_Misc': 'Swartz, Brian', 'Total_Points': 66.0},
     {'TOT_PTS_Misc': 'Blackwell, Devon', 'Total_Points': 60.0},
     {'TOT_PTS_Misc': 'Blasinsky, Scott', 'Total_Points': 60.0},
     {'TOT_PTS_Misc': 'Bolden, Antonio', 'Total_Points': 60.0},
     {'TOT_PTS_Misc': 'Carter III, Laymon', 'Total_Points': 60.0},
     {'TOT_PTS_Misc': 'Coleman, Johnathan', 'Total_Points': 60.0},
     {'TOT_PTS_Misc': 'Kovach, Alex', 'Total_Points': 60.0},
     {'TOT_PTS_Misc': 'Smith, Ryan', 'Total_Points': 60.0},
     {'TOT_PTS_Misc': 'Venditti, Nick', 'Total_Points': 60.0}]
    
  9. from https://stackoverflow.com/questions/1143671/python-sorting-list-of-dictionaries-by-multiple-keys by cc-by-sa and MIT license