আমি অভিধানের একটি মান দ্বারা অভিধানের তালিকাটি কীভাবে সাজান?


1892

আমার কাছে অভিধানের একটি তালিকা রয়েছে এবং প্রতিটি আইটেম একটি নির্দিষ্ট সম্পত্তি মান অনুসারে বাছাই করা চাই।

নীচে অ্যারে বিবেচনা করুন,

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

যখন বাছাই করা nameউচিত, হয়ে উঠবে

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

উত্তর পঠন এবং এর খুঁজছি operator.itemgetter । আমি কি একই প্রক্রিয়াতে একাধিক মান বাছাই করতে পারি (উদাহরণস্বরূপ আমাদের রয়েছে [{'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') সম্পাদনা: পরীক্ষিত, এবং এটি কাজ করছে তবে আমি কীভাবে নোট DESC করতে হবে এবং ASC নামকরণ করতে জানি না।
ক্লদিউ

উত্তর:


2462

এটি কোনও সিএমপি পরিবর্তে কোনও কী ব্যবহার করে ক্লিনার দেখায়:

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

বা জেএফেসেস্টিয়ান এবং অন্যরা যেমন পরামর্শ দিয়েছে,

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

সম্পূর্ণতার জন্য (ফিটজগেরাল্ডস্টিলের মন্তব্যে যেমন উল্লেখ করা হয়েছে), উতরাই reverse=Trueবাছাই করতে যুক্ত করুন

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

34
কী ব্যবহার করা কেবল পরিষ্কার নয় তবে আরও কার্যকর।
jfs

5
দ্রুততম উপায় হ'ল নতুন তালিকা.বিপরীত () বিবৃতি যুক্ত করা। অন্যথায় আপনি সিএমপি = ল্যাম্বদা এক্স, ওয়াই: - সিএমপি (এক্স ['নাম'], y ['নাম']) এর মতো একটি তুলনা সংজ্ঞায়িত করতে পারেন।
মারিও এফ

3
যদি সাজানোর মানটি এমন একটি সংখ্যা হিসাবে আপনি বলতে পারেন: ল্যাম্বডা কে: (কে ['বয়স'] * -1) বিপরীত সাজানোর জন্য
ফিলুমিনাটি

2
এটাও tuples একটি তালিকা প্রযোজ্য, যদি আপনি ব্যবহার itemgetter(i)যেখানে iউপর সাজাতে tuple উপাদান সূচি।
রেডিক্যান্ড

42
itemgetterএকাধিক যুক্তি গ্রহণ করে: itemgetter(1,2,3)এটি এমন একটি ফাংশন যা একটি টুপলের মতো ফেরত দেয় obj[1], obj[2], obj[3], তাই আপনি জটিল প্রকারের জন্য এটি ব্যবহার করতে পারেন।
বাকুরিউ

165
import operator

কীগুলির সাহায্যে অভিধানের তালিকা বাছাই করুন = 'নাম':

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

কী = 'বয়স' অনুসারে অভিধানের তালিকা সাজানোর জন্য:

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

9
যাইহোক নাম এবং বয়স একত্রিত করতে? (এসকিউএল অর্ডার নাম অনুসারে, বয়স?)
মনোজোহনি

28
@ মোমোজনহ্নি: হ্যাঁ, কেবল একটি চাবি ফিরে আসবে key=lambda k: (k['name'], k['age']),। (বা key=itemgetter('name', 'age')) টিপলগুলি cmpপ্রতিটি উপাদানকে পালাক্রমে তুলনা করবে। এটি রক্তাক্ত উজ্জ্বল।
ক্লডিউ

1
ডকুমেন্টেশনে ( ডকস.পিথন.অর্গ / ২ / টিউটোরিয়াল / ডেটাস্ট্রিকচারস html ) forচ্ছিকkey যুক্তি list.sort()বর্ণিত হয়নি। কোন ধারণা কোথায় এটি?
টিটিটি

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

... ল্যাম্বদা আইএমও, এর চেয়ে বোঝা সহজ operator.itemgetter, তবে ওয়াইএমএমভি।


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 এর মন্তব্যটি তাত্ক্ষণিকভাবে আমার কাছে পরিষ্কার হয়নি তাই আমি নিম্নলিখিতটি পেয়েছি। আপনি এনজেজেকি 2 এর পরামর্শ অনুসারে মাত্র দু'বার বাছাই করতে পারেন, বা শীর্ষ উত্তরে অপারেটর.ইটিমেজেটারে একাধিক যুক্তি পাস করতে পারেন। লিঙ্ক: stackoverflow.com/questions/5212870/...
Permafacture

15
স্ট্রিংয়ে রূপান্তর করার দরকার নেই। কী হিসাবে একটি tuple ফিরে।
উইনস্টন ইওয়ার্ট

একাধিক বার বাছাই হ্যাক ছাড়া সবচেয়ে সহজ পদ্ধিতি হল জেনেরিক সমাধান: stackoverflow.com/a/29849371/1805397
Wouter bolsterlee

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

'কী' একটি স্বেচ্ছাসেবী মান অনুসারে বাছাই করতে ব্যবহৃত হয় এবং 'আইটেমজিটার' প্রতিটি আইটেমের 'নাম' বৈশিষ্ট্যে সেট করে value


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

আরো রুপান্তর পার্ল Schwartzian

কম্পিউটার সায়েন্সে শোয়ার্জিয়ান ট্রান্সফর্ম হ'ল পার্ল প্রোগ্রামিং আইডিয়াম যা আইটেমের তালিকা বাছাইয়ের দক্ষতা উন্নত করতে ব্যবহৃত হয়। এই আইডিয়োম তুলনামূলক ভিত্তিক বাছাইয়ের জন্য উপযুক্ত যখন অর্ডারটি আসলে উপাদানগুলির একটি নির্দিষ্ট সম্পত্তি (কী) এর ক্রমের উপর ভিত্তি করে থাকে, যেখানে সেই সম্পত্তিটি গণনা করা হয় নিবিড় ক্রিয়াকলাপ যা ন্যূনতম সংখ্যক বার করা উচিত। শোয়ার্জিয়ান ট্রান্সফর্মটি উল্লেখযোগ্য যে এটি নামযুক্ত অস্থায়ী অ্যারে ব্যবহার করে না।


9
পাইথন সমর্থন করে key=জন্য .sort2.4 থেকে, বছর 2004 যে, এটা করে Schwartzian বাছাই কোড মধ্যেই সি রুপান্তর; সুতরাং এই পদ্ধতিটি কেবল পাইথনস ২.০-২.৩ এ কার্যকর is যার সবগুলিই 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

এখানে বিকল্প সাধারণ সমাধান রয়েছে - এটি কী এবং মান দ্বারা ডিকের উপাদানগুলি সাজায় s এর সুবিধা - কীগুলি নির্দিষ্ট করার দরকার নেই, এবং কিছু অভিধানে কিছু কী অনুপস্থিত থাকলে এটি এখনও কাজ করবে।

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
আমি আপনার কোডটি চালিয়েছি এবং সময়রেখায় একটি ভুল খুঁজে পেয়েছি Meth বৃহত্তর পদ্ধতি পান্ডাদের জন্য টাইমার আর্গুমেন্ট: আপনি "সেটআপ_স্মাল" নির্দিষ্ট করেন যেখানে এটি "সেটআপ_লার্জ" হওয়া উচিত। এই আরগ পরিবর্তন করার ফলে প্রোগ্রামটি শেষ না করেই চলতে পারে এবং আমি এটি 5 মিনিটেরও বেশি পরে থামিয়ে দিয়েছি। আমি যখন এটি "টাইমাইট (1)" দিয়ে চালিত করেছি, বড় পদ্ধতিটি পান্ডা 7.3 সেকেন্ডে শেষ করেছে, এলসি বা এলসি 2 এর চেয়েও খারাপ।
clp2

আপনি বেশ সঠিক, এটা আমার পক্ষ থেকে একটি তদারকি ছিল। আমি আর বড় মামলার জন্য এটি সুপারিশ! আমি সম্ভাবনা হিসাবে সহজভাবে অনুমতি দেওয়ার জন্য উত্তরটি সম্পাদনা করেছি, ব্যবহারের ক্ষেত্রে এখনও বিতর্ক চলছে for
এবি sobh

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

আমি ফিল্টার ডাব্লু / ল্যাম্বডায়ার একটি বড় অনুরাগী হয়ে উঠছি তবে আপনি সময়ের জটিলতা বিবেচনা করলে এটি সেরা বিকল্প নয়

প্রথম বিকল্প

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 সর্বোত্তম c

# 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 ইউএসসি সেরা


2

পারফরম্যান্স যদি উদ্বেগের বিষয় থাকে তবে আমি হস্ত-কারুকৃত ফাংশনগুলির চেয়ে বিল্ট-ইন ফাংশনগুলি দ্রুত সম্পাদন করার operator.itemgetterপরিবর্তে ব্যবহার করব lambdaitemgetterফাংশন প্রায় 20% যতো তাড়াতাড়ি সঞ্চালন বলে মনে হয় lambdaআমার পরীক্ষার উপর ভিত্তি করে।

Https://wiki.python.org/moin/PythonSpeed থেকে :

তেমনি, বিল্টিন ফাংশনগুলি হস্তনির্মিত সমতুল্যের তুলনায় দ্রুত চলে। উদাহরণস্বরূপ, মানচিত্র (অপারেটর.এডিডি, ভি 1, ভি 2) মানচিত্রের চেয়ে দ্রুত (ল্যাম্বদা এক্স, ওয়াই: এক্স + ওয়াই, ভি 1, ভি 2)।

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])
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.