मैं शब्दकोश के मूल्य द्वारा शब्दकोशों की सूची कैसे छाँटूँ?


1892

मेरे पास शब्दकोशों की एक सूची है और चाहते हैं कि प्रत्येक आइटम को एक विशिष्ट संपत्ति मूल्यों द्वारा क्रमबद्ध किया जाए।

नीचे दिए गए सरणी को ध्यान में रखें,

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

जब क्रमबद्ध nameहो जाए, बन जाना चाहिए

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

उत्तर को पढ़ना और ऑपरेटर पर क्लिक करना । क्या मैं एक ही प्रक्रिया (उदाहरण के लिए हमारे पास [{'name':'Bart', 'age':10, 'note':3},{'name':'Homer','age':10,'note':2},{'name':'Vasile','age':20,'note':3}] और उपयोग करने के लिए: from operator import itemgetter newlist = sorted(old_list, key=itemgetter(-'note','name') EDIT: परीक्षण किया गया है, और यह काम कर रहा है, लेकिन मैं इसे DES DES और ASC का नाम नोट करना नहीं जानता।
क्लाउडिया

जवाबों:


2462

यह एक 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)

34
कुंजी का उपयोग न केवल क्लीनर, बल्कि अधिक कुशल भी है।
15

5
सबसे तेज़ तरीका एक newlist.reverse () स्टेटमेंट जोड़ना होगा। अन्यथा आप cmp = lambda x, y: - cmp (x ['name'], y ['name']) जैसी तुलना को परिभाषित कर सकते हैं।
मारियो एफ

3
अगर सॉर्ट वैल्यू एक संख्या है जो आप कह सकते हैं: लैम्ब्डा k: (k ['उम्र'] * -1) रिवर्स सॉर्ट प्राप्त करने के लिए
फिलुमिनति

2
यह टुपल्स की एक सूची पर भी लागू होता है, यदि आप इसका उपयोग करते हैं itemgetter(i)जहां iपर सॉर्ट करने के लिए टपल तत्व का सूचकांक है।
त्रिकोणीय

42
itemgetterएक से अधिक तर्क स्वीकार करता है: itemgetter(1,2,3)एक ऐसा कार्य है जो एक टपल को वापस लौटाता है obj[1], obj[2], obj[3], इसलिए आप इसका उपयोग जटिल प्रकार से करने के लिए कर सकते हैं।
बकुरीउ

166
import operator

कुंजी = 'नाम' द्वारा शब्दकोशों की सूची को क्रमबद्ध करने के लिए:

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

कुंजी = 'आयु' द्वारा शब्दकोशों की सूची को क्रमबद्ध करने के लिए:

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

9
वैसे भी नाम और उम्र को मिलाने के लिए? (जैसे SQL ORDER BY नाम, उम्र?)
monojohnny

28
@monojohnny: हाँ, बस एक वापसी महत्वपूर्ण है, एक key=lambda k: (k['name'], k['age'])। (या key=itemgetter('name', 'age'))। टपल की cmpबारी में प्रत्येक तत्व की तुलना करेंगे। यह शानदार है।
२१:२१

1
प्रलेखन ( docs.python.org/2/tutorial/datastructures.html ) में वैकल्पिक keyतर्क list.sort()का वर्णन नहीं किया गया है। किसी भी विचार है कि कहाँ खोजने के लिए?
TTT

2
@ टीटीटी: दोस्तों और दोस्तों के लिए लाइब्रेरी डॉक्यूमेंटेशन देखें list
केविन

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

... लंबोदर, IMO, समझने में आसान है operator.itemgetter, लेकिन YMMV।


51

यदि आप कई कुंजियों द्वारा सूची को क्रमबद्ध करना चाहते हैं, तो आप निम्न कार्य कर सकते हैं:

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

यह बजाय हैकिश है, क्योंकि यह तुलना के लिए एकल स्ट्रिंग प्रतिनिधित्व में मूल्यों को परिवर्तित करने पर निर्भर करता है, लेकिन यह नकारात्मक सहित संख्याओं के लिए अपेक्षित के रूप में काम करता है (हालांकि यदि आप संख्याओं का उपयोग कर रहे हैं तो आपको अपने स्ट्रिंग को शून्य पैडिंग के साथ उचित रूप से प्रारूपित करने की आवश्यकता होगी)


2
सॉर्टर्स का उपयोग करके सॉर्ट किया गया जो स्थिर है, आप कई बार सॉर्ट करने के लिए कई मानदंडों पर सॉर्ट कर सकते हैं
njzk2

njzk2 की टिप्पणी मेरे लिए तुरंत स्पष्ट नहीं थी इसलिए मैंने निम्नलिखित पाया। आप बस दो बार छांट सकते हैं जैसे कि njzk2 सुझाव देता है, या शीर्ष उत्तर में oper.itemgetter के लिए कई तर्क पारित करता है। लिंक: stackoverflow.com/questions/5212870/…
पेराफैक्ट्योर

15
स्ट्रिंग में बदलने की आवश्यकता नहीं है। बस कुंजी के रूप में एक टपल लौटें।
विंस्टन इर्वर्ट

हैक्स के बिना कई बार सॉर्ट करना सबसे आसान जेनेरिक सॉल्यूशन है: stackoverflow.com/a/29849371/1805397
wouter bolsterlee

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

'कुंजी' का उपयोग एक मनमाना मूल्य द्वारा सॉर्ट करने के लिए किया जाता है और 'आइटमगेटर' उस मूल्य को प्रत्येक आइटम के 'नाम' विशेषता पर सेट करता है।


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


19

आप एक कस्टम तुलना फ़ंक्शन का उपयोग कर सकते हैं, या आप एक फ़ंक्शन में पास हो सकते हैं जो एक कस्टम सॉर्ट कुंजी की गणना करता है। यह आमतौर पर अधिक कुशल होता है क्योंकि कुंजी केवल एक बार प्रति आइटम की गणना की जाती है, जबकि तुलनात्मक फ़ंक्शन को कई बार कहा जाता है।

आप इसे इस तरह से कर सकते हैं:

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

19

पर्ल से श्वार्टज़ियन परिवर्तन का उपयोग करना,

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

करना

sort_on = "name"
decorated = [(dict_[sort_on], dict_) for dict_ in py]
decorated.sort()
result = [dict_ for (key, dict_) in decorated]

देता है

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

पर्ल स्क्वार्ट्जियन ट्रांसफॉर्म पर अधिक

कंप्यूटर विज्ञान में, श्वार्ट्ज़ियन ट्रांसफ़ॉर्म एक पर्ल प्रोग्रामिंग मुहावरा है जिसका उपयोग वस्तुओं की सूची को छाँटने की दक्षता में सुधार के लिए किया जाता है। यह मुहावरे तुलना-आधारित छँटाई के लिए उपयुक्त है जब आदेश वास्तव में तत्वों की एक निश्चित संपत्ति (कुंजी) के आदेश पर आधारित होता है, जहाँ उस संपत्ति की गणना एक गहन ऑपरेशन है जिसे कम से कम कई बार किया जाना चाहिए। श्वार्ट्ज़ियन ट्रांसफ़ॉर्म उल्लेखनीय है कि यह अस्थायी सरणियों का उपयोग नहीं करता है।


9
पाइथन ने 2.4 के key=लिए समर्थन किया है .sort, वह वर्ष 2004 है, यह सी में कोडिंग कोड के भीतर श्वार्टज़ियन रूपांतरण करता है; इस प्रकार यह विधि केवल पायथन 2.0-2.3 पर उपयोगी है। जिनमें से सभी 12 साल से अधिक पुराने हैं।
अंती हापाला


12

कभी-कभी हमें lower()उदाहरण के लिए उपयोग करने की आवश्यकता होती है

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}]

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)

10

पांडा पैकेज का उपयोग करना एक अन्य विधि है, हालांकि यह बड़े पैमाने पर रनटाइम है, दूसरों द्वारा प्रस्तावित अधिक पारंपरिक तरीकों की तुलना में बहुत धीमा है:

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 +) सूची की सूची:

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

3
मैंने आपका कोड चलाया और timeit में एक गलती पाई। बड़ी विधि पंडों के लिए चिमटा आ गया: आप "setup_small" को निर्दिष्ट करते हैं जहां इसे "setup_large" होना चाहिए। उस arg को बदलने से प्रोग्राम बिना फिनिशिंग के चलने लगा, और मैंने इसे 5 मिनट से अधिक समय के बाद बंद कर दिया। जब मैंने इसे "टाइमिट (1)" के साथ चलाया, तो बड़े विधि पंडों ने 7.3 सेकंड में समाप्त कर दिया, एलसी या एलसी 2 से बहुत खराब।
clp2

आप बिलकुल सही कह रहे हैं, यह मेरी ओर से काफी निगरानी थी। मैं अब बड़े मामलों के लिए इसकी सिफारिश नहीं करता! मैंने उत्तर को केवल एक संभावना के रूप में अनुमति देने के लिए संपादित किया है, उपयोग का मामला अभी भी बहस के लिए तैयार है।
एबी सोब 22

6

यदि आपको मूल listकी आवश्यकता नहीं है dictionaries, तो आप इसे sort()कस्टम कुंजी फ़ंक्शन का उपयोग करके विधि के साथ इन-प्लेस संशोधित कर सकते हैं ।

मुख्य समारोह:

def get_name(d):
    """ Return the value of a key in a dictionary. """

    return d["name"]

listक्रमबद्ध करना:

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

इसे जगह में छाँटना:

data_one.sort(key=get_name)

यदि आपको मूल की आवश्यकता है , तो इसे और कुंजी फ़ंक्शन को पास listकरने वाले sorted()फ़ंक्शन को कॉल करें list, फिर दिए गए रिटर्न listको एक नए चर में असाइन करें :

data_two = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
new_data = sorted(data_two, key=get_name)

मुद्रण data_oneऔर new_data

>>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]

6

मान लीजिए कि मेरे पास 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

चेक इस बाहर।


3

मैं फ़िल्टर w / lambda का एक बड़ा प्रशंसक रहा हूं, लेकिन समय की जटिलता पर विचार करें तो यह सबसे अच्छा विकल्प नहीं है

पहला विकल्प

sorted_list = sorted(list_to_sort, key= lambda x: x['name'])
# returns list of values

दूसरा विकल्प

list_to_sort.sort(key=operator.itemgetter('name'))
#edits the list, does not return a new list

निष्पादन समय की तेज तुलना

# First option
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" "sorted_l = sorted(list_to_sort, key=lambda e: e['name'])"

1000000 छोरों, 3 का सबसे अच्छा: 0.736 usec प्रति पाश

# Second option 
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" -s "import operator" "list_to_sort.sort(key=operator.itemgetter('name'))"

1000000 लूप, 3 का सर्वश्रेष्ठ: 0.438 usec प्रति लूप


2

यदि प्रदर्शन एक चिंता का विषय है, तो मैं operator.itemgetterइसके बजाय उपयोग करूँगा lambdaजैसे कि अंतर्निहित कार्य हाथ से तैयार किए गए कार्यों की तुलना में तेज़ी से करते हैं। itemgetterसमारोह लगभग 20% से अधिक तेजी से प्रदर्शन करने के लिए लगता है lambdaमेरी परीक्षण पर आधारित।

से https://wiki.python.org/moin/PythonSpeed :

इसी तरह, अंतर्निहित कार्य हाथ से निर्मित समकक्षों की तुलना में तेजी से चलते हैं। उदाहरण के लिए, मानचित्र (संचालक। Vd, v1, v2) मानचित्र (लंबो x, y: x + y, v1, v2) से तेज है।

यहाँ lambdaबनाम का उपयोग कर छँटाई गति की तुलना है itemgetter

import random
import operator

# create a list of 100 dicts with random 8-letter names and random ages from 0 to 100.
l = [{'name': ''.join(random.choices(string.ascii_lowercase, k=8)), 'age': random.randint(0, 100)} for i in range(100)]

# Test the performance with a lambda function sorting on name
%timeit sorted(l, key=lambda x: x['name'])
13 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# Test the performance with itemgetter sorting on name
%timeit sorted(l, key=operator.itemgetter('name'))
10.7 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# Check that each technique produces same sort order
sorted(l, key=lambda x: x['name']) == sorted(l, key=operator.itemgetter('name'))
True

दोनों तकनीक समान क्रम में सूची को सॉर्ट करती हैं (कोड ब्लॉक में अंतिम विवरण के निष्पादन द्वारा सत्यापित) लेकिन एक थोड़ा तेज है।


-1

आप निम्न कोड का उपयोग कर सकते हैं

sorted_dct = sorted(dct_name.items(), key = lambda x : x[1])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.