我有一个字典列表,希望每个条目都按照特定的属性值排序。
考虑到下面的数组,
1 | [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}] |
当按
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在评论中指出的),添加
1 | newlist = sorted(l, key=itemgetter('name'), reverse=True) |
1 | import operator |
按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'])) |
(3年后)编辑后添加:
新的
1 | my_list = sorted(my_list, key=lambda k: k['name']) |
…在我看来,lambda比
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) |
但是标准库包含一个获取任意对象项的通用例程:
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) |
有时候我们需要使用
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的简并情况。
如果不需要
主要功能:
1 2 3 4 | def get_name(d): """ Return the value of a key in a dictionary.""" return d["name"] |
待排序的
1 | data_one = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}] |
就地排序:
1 | data_one.sort(key=get_name) |
如果需要原始的
1 2 | data_two = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}] new_data = sorted(data_two, key=get_name) |
打印
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]) |