我有一个字典列表,希望每个条目都按照特定的属性值排序。
考虑到下面的数组,
1
| [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}] |
当按name排序时,应该变成
1
| [{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}] |
它可能看起来更干净使用一个关键而不是一个cmp:
1
| newlist = sorted(list_to_be_sorted, key=lambda k: k['name']) |
或作为参考塞巴斯蒂安和其他人认为,
1 2
| from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name')) |
为了完整性(正如fitzgeraldsteele在评论中指出的),添加reverse=True来降序排序
1
| newlist = sorted(l, key=itemgetter('name'), reverse=True) |
按key='name'对字典列表进行排序:
1
| list_of_dicts.sort(key=operator.itemgetter('name')) |
按key='age'对字典列表进行排序:
1
| list_of_dicts.sort(key=operator.itemgetter('age')) |
如果你想按多个键对列表排序,你可以这样做:
1 2
| my_list = [{'name':'Homer', 'age':39}, {'name':'Milhouse', 'age':10}, {'name':'Bart', 'age':10} ]
sortedlist = sorted(my_list , key=lambda elem:"%02d %s" % (elem['age'], elem['name'])) |
这是相当笨拙的,因为它依赖于将值转换为单个字符串表示来进行比较,但是对于包括负数在内的数字,它的工作方式与预期的一样(尽管如果使用数字,则需要使用零划片适当地格式化字符串)
1 2 3
| my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
my_list.sort(lambda x,y : cmp(x['name'], y['name'])) |
my_list现在将是您想要的。
(3年后)编辑后添加:
新的key参数更有效、更简洁。一个更好的答案是:
1
| my_list = sorted(my_list, key=lambda k: k['name']) |
…在我看来,lambda比operator.itemgetter更容易理解,但是YMMV。
1 2
| import operator
a_list_of_dicts.sort(key=operator.itemgetter('name')) |
'key'用于按任意值排序,'itemgetter'将该值设置为每个项目的'name'属性。
我想你的意思是:
1
| [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}] |
这样排序:
1
| sorted(l,cmp=lambda x,y: cmp(x['name'],y['name'])) |
使用Perl中的Schwartzian转换,
1
| py = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}] |
做
1 2 3 4
| sort_on ="name"
decorated = [(dict_[sort_on], dict_) for dict_ in py]
decorated.sort()
result = [dict_ for (key, dict_) in decorated] |
给了
1 2
| >>> result
[{'age': 10, 'name': 'Bart'}, {'age': 39, 'name': 'Homer'}] |
更多关于Perl Schwartzian转换的信息
In computer science, the Schwartzian transform is a Perl programming
idiom used to improve the efficiency of sorting a list of items. This
idiom is appropriate for comparison-based sorting when the ordering is
actually based on the ordering of a certain property (the key) of the
elements, where computing that property is an intensive operation that
should be performed a minimal number of times. The Schwartzian
Transform is notable in that it does not use named temporary arrays.
1 2 3 4 5 6 7
| a = [{'name':'Homer', 'age':39}, ...]
# This changes the list a
a.sort(key=lambda k : k['name'])
# This returns a new list (a is not modified)
sorted(a, key=lambda k : k['name']) |
您可以使用自定义比较函数,也可以传入计算自定义排序键的函数。这通常更有效,因为每个项只计算一次键值,而比较函数将被调用多次。
你可以这样做:
1 2 3
| def mykey(adict): return adict['name']
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=mykey) |
但是标准库包含一个获取任意对象项的通用例程:itemgetter。所以试试这个:
1 2 3
| from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name')) |
您必须实现自己的比较函数,该函数将根据名称键的值比较字典。参见如何从PythonInfo Wiki中排序
我试着这样做:
1
| my_list.sort(key=lambda x: x['name']) |
它也适用于整数。
这是另一种通用解决方案——它根据键和值对dict的元素进行排序。它的优点——不需要指定键,而且如果某些字典中缺少一些键,它仍然可以工作。
1 2 3 4 5 6 7 8 9 10 11
| def sort_key_func(item):
""" helper function used to sort list of dicts
:param item: dict
:return: sorted list of tuples (k, v)
"""
pairs = []
for k, v in item.items():
pairs.append((k, v))
return sorted(pairs)
sorted(A, key=sort_key_func) |
有时候我们需要使用lower()作为例子
1 2 3 4 5 6 7 8 9 10 11
| lists = [{'name':'Homer', 'age':39},
{'name':'Bart', 'age':10},
{'name':'abby', 'age':9}]
lists = sorted(lists, key=lambda k: k['name'])
print(lists)
# [{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}, {'name':'abby', 'age':9}]
lists = sorted(lists, key=lambda k: k['name'].lower())
print(lists)
# [ {'name':'abby', 'age':9}, {'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}] |
使用panda包是另一种方法,尽管它在大规模运行时比其他人提出的更传统的方法慢得多:
1 2 3 4 5 6
| import pandas as pd
listOfDicts = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
df = pd.DataFrame(listOfDicts)
df = df.sort_values('name')
sorted_listOfDicts = df.T.to_dict().values() |
下面是一个小列表和一个大的(100k+) dicts列表的一些基准值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| setup_large ="listOfDicts = [];\
[listOfDicts.extend(({'name':'Homer', 'age':39}, {'name':'Bart', 'age':10})) for _ in range(50000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(listOfDicts);"
setup_small ="listOfDicts = [];\
listOfDicts.extend(({'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(listOfDicts);"
method1 ="newlist = sorted(listOfDicts, key=lambda k: k['name'])"
method2 ="newlist = sorted(listOfDicts, key=itemgetter('name'))"
method3 ="df = df.sort_values('name');\
sorted_listOfDicts = df.T.to_dict().values()"
import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method LC2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))
t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method LC2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup_large)
print('Large Method Pandas: ' + str(t.timeit(1)))
#Small Method LC: 0.000163078308105
#Small Method LC2: 0.000134944915771
#Small Method Pandas: 0.0712950229645
#Large Method LC: 0.0321750640869
#Large Method LC2: 0.0206089019775
#Large Method Pandas: 5.81405615807 |
假设我有一个字典D,它的元素在下面。要进行排序,只需使用关键参数in ordered来传递自定义函数,如下所示
1 2 3 4 5 6 7 8
| D = {'eggs': 3, 'ham': 1, 'spam': 2}
def get_count(tuple):
return tuple[1]
sorted(D.items(), key = get_count, reverse=True)
or
sorted(D.items(), key = lambda x: x[1], reverse=True) avoiding get_count function call |
https://wiki.python.org/moin/HowTo/Sorting/#Key_Functions
下面是我对一个有关按多列排序的问题的回答。它也适用于列数只有1的简并情况。
如果不需要dictionaries的原始list,可以使用自定义键函数用sort()方法就地修改它。
主要功能:
1 2 3 4
| def get_name(d):
""" Return the value of a key in a dictionary."""
return d["name"] |
待排序的list:
1
| data_one = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}] |
就地排序:
1
| data_one.sort(key=get_name) |
如果需要原始的list,调用sorted()函数,传递给它list和key函数,然后将返回的排序后的list赋给一个新变量:
1 2
| data_two = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
new_data = sorted(data_two, key=get_name) |
打印data_one和new_data。
1 2 3 4
| >>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}] |
如果要考虑性能,可以使用itemgetter。itemgetter通常比lambda运行得快一些。
1 2
| from operator import itemgetter
result = sorted(data, key=itemgetter('age')) # this will sort list by property order 'age'. |
您可以使用以下代码
1
| sorted_dct = sorted(dct_name.items(), key = lambda x : x[1]) |
|