또는 실제로 여러 키로 사전 목록을 정렬하려면 어떻게해야합니까?
사전 목록이 있습니다.
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 함수로 전달되는 임의의 수의 키에 대해 목록을 정렬하는 람다 줄을 어떻게 사용할 수 있으며, sortkey에 여러 키가있을 수 있으며 역 정렬이 필요한 키를 식별 할 수 있다는 점을 고려합니다. 앞에 ‘-‘가 있습니까?
답변
이 답변은 사전의 모든 종류의 열에 대해 작동합니다. 부정 된 열은 숫자 일 필요가 없습니다.
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
인수를 제거함)에서 작동합니다 sort
.
from operator import itemgetter as i
from functools import cmp_to_key
def cmp(x, y):
"""
Replacement for built-in function cmp that was removed in Python 3
Compare the two objects x and y and return an integer according to
the outcome. The return value is negative if x < y, zero if x == y
and strictly positive if x > y.
https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
"""
return (x > y) - (x < y)
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에서 사용자 지정 정렬을 수행하려면 어떻게해야합니까?
답변
이 기사 에는이를 수행하는 다양한 기술에 대한 멋진 개요가 있습니다. 요구 사항이 “전체 양방향 다중 키”보다 간단하다면 살펴보십시오. 받아 들여지는 대답과 방금 참조 한 블로그 게시물이 어떤 방식 으로든 서로 영향을 미쳤지 만 어떤 순서인지는 모르겠습니다.
링크가 죽는 경우 위에서 다루지 않은 예제에 대한 매우 빠른 개요가 있습니다.
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']))
답변
나는이 다소 오래된 질문 알지만, 답변 아무도 파이썬 등의 정렬 루틴 안정적인 정렬 순서를 보장 언급하지 list.sort()
와 sorted()
동일 원래 순서를 유지 비교할 항목을 의미한다.
즉 ORDER BY name ASC, age DESC
, 사전 목록에 해당하는 (SQL 표기법 사용) 다음과 같이 수행 할 수 있습니다.
items.sort(key=operator.itemgetter('age'), reverse=True)
items.sort(key=operator.itemgetter('name'))
항목이 먼저 ‘lesser’속성 age
(내림차순) 으로 정렬 된 다음 ‘major’속성으로 name
정렬되어 올바른 최종 순서로 이어지는 방식에 유의하세요 .
반전 / 반전은 마이너스 기호를 앞에 넣어 부정 할 수있는 숫자뿐만 아니라 모든 주문 가능한 유형에 대해 작동합니다.
그리고 (적어도) CPython에서 사용되는 Timsort 알고리즘 때문에 실제로 이것은 실제로 다소 빠릅니다.
답변
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']))
답변
여러 열에서 2D 배열을 정렬하기 위해 다음을 사용합니다.
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]]
답변
오늘 비슷한 문제가있었습니다. 숫자 값을 내림차순으로, 문자열 값을 오름차순으로 사전 항목을 정렬해야했습니다. 충돌하는 방향 문제를 해결하기 위해 정수 값을 부정했습니다.
다음은 내 솔루션의 변형입니다-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}]
답변
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'}]
구문 분석은 약간 취약하지만 적어도 키 사이에 다양한 수의 공백을 허용합니다.