python حلقة - كيف يمكنني فرز قائمة القواميس حسب قيم القاموس في بايثون؟




التكرار برنامج (15)

حصلت على قائمة من القواميس وتريد أن يتم فرزها حسب قيمة ذلك القاموس.

هذه

[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

فرز حسب الاسم ، يجب أن تصبح

[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]

Answers

قد يبدو الأمر أكثر نظافة باستخدام مفتاح بدلاً من cmp:

newlist = sorted(list_to_be_sorted, key=lambda k: k['name']) 

أو كما اقترح JFSebastian وآخرون ،

from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name')) 

للتأكد من اكتمالها (كما هو موضح في التعليقات من قبل fitzgeraldsteele) ، أضف reverse=True للترتيب التنازلي

newlist = sorted(l, key=itemgetter('name'), reverse=True)

دعنا نقول أنا h'v قاموس D مع العناصر أدناه. لفرز استخدام وسيطة مفتاح في فرز لتمرير الدالة المخصصة كما هو موضح أدناه

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


يعد استخدام حزمة الباندا طريقة أخرى ، على الرغم من أن وقت التشغيل على نطاق واسع أبطأ بكثير من الطرق التقليدية التي اقترحها الآخرون:

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()

فيما يلي بعض القيم المرجعية لقائمة صغيرة وقائمة كبيرة (100 كيلو +) من dicts:

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

هنا هو الحل العام البديل - يقوم بفرز عناصر من مفاتيح بواسطة مفاتيح والقيم. ميزة ذلك - لا حاجة لتحديد المفاتيح ، وستظل تعمل إذا كانت بعض المفاتيح مفقودة في بعض القواميس.

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)

أعتقد أنك قصدت:

[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

سيتم فرز هذا على النحو التالي:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))

import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))

يتم استخدام "مفتاح" للفرز حسب القيمة التعسفية و "itemgetter" الذي يقوم بتعيين هذه القيمة إلى سمة "اسم" لكل عنصر.




إذا كنت تريد فرز القائمة بواسطة مفاتيح متعددة ، فيمكنك القيام بما يلي:

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']))

إنه بالأحرى هجاء ، لأنه يعتمد على تحويل القيم إلى تمثيل سلسلة مفرد للمقارنة ، ولكنه يعمل كما هو متوقع للأرقام بما في ذلك الأرقام السلبية (على الرغم من أنك ستحتاج إلى تنسيق السلسلة الخاصة بك بشكل مناسب مع أعمدة غير صالحة إذا كنت تستخدم الأرقام)


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']) 

يمكنك استخدام دالة مقارنة مخصصة أو يمكنك تمرير دالة تقوم بحساب مفتاح فرز مخصص. عادة ما يكون ذلك أكثر كفاءة حيث يتم حساب المفتاح مرة واحدة فقط لكل عنصر ، بينما يتم استدعاء وظيفة المقارنة مرات أكثر.

يمكنك فعلها بهذه الطريقة:

def mykey(adict): return adict['name']
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=mykey)

لكن المكتبة القياسية تحتوي على روتين عام للحصول على عناصر الكائنات التعسفية: itemgetter . لذا جرب هذا بدلاً من ذلك:

from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))

جربت شيئًا كهذا:

my_list.sort(key=lambda x: x['name'])

عملت للأعداد الصحيحة كذلك.


import operator

لفرز قائمة القواميس من خلال key = 'name':

list_of_dicts.sort(key=operator.itemgetter('name'))

لفرز قائمة القواميس بالمفتاح = "العمر":

list_of_dicts.sort(key=operator.itemgetter('age'))

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 الجديدة هي أكثر كفاءة ومتانة. تبدو الإجابة الأفضل الآن كما يلي:

my_list = sorted(my_list, key=lambda k: k['name'])

... إن lambda ، IMO ، أسهل في الفهم من operator.itemgetter ، لكن YMMV.


def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])




python list sorting dictionary data-structures