কীভাবে অবজেক্টগুলির একটি বৈশিষ্ট্যের উপর ভিত্তি করে অবজেক্টের একটি তালিকা সাজানো যায়?


803

পাইথন অবজেক্টের একটি তালিকা পেয়েছি যা আমি নিজেরাই বস্তুর একটি বৈশিষ্ট্য অনুসারে বাছাই করতে চাই। তালিকাটি দেখে মনে হচ্ছে:

>>> ut
[<Tag: 128>, <Tag: 2008>, <Tag: <>, <Tag: actionscript>, <Tag: addresses>,
 <Tag: aes>, <Tag: ajax> ...]

প্রতিটি বস্তুর একটি গণনা রয়েছে:

>>> ut[1].count
1L

আমার নামার ক্রম সংখ্যা অনুসারে বাছাই করতে হবে।

আমি এর জন্য বেশ কয়েকটি পদ্ধতি দেখেছি, তবে আমি পাইথনে সেরা অনুশীলন খুঁজছি।



1
যারা পাইথনে বাছাই সম্পর্কে আরও তথ্যের সন্ধান করছেন তাদের জন্য কীভাবে বাছাই করা হচ্ছে।
জিয়েকোমন

1
অপারেটর.আত্রট্রেটার ('অ্যাট্রিবিউট_নেম') বাদে আপনি উদ্দেশ্যমূলকভাবে বাস্তবায়নটি বাইরে রেখে অবজেক্ট_লিস্ট.সোর্ট (কী = আমার_সোর্টিং_ফান্টর ('মাই_কি')) এর মতো কী হিসাবেও ফান্টেক্টর ব্যবহার করতে পারেন।
বিজয় শঙ্কর

উত্তর:


1312
# To sort the list in place...
ut.sort(key=lambda x: x.count, reverse=True)

# To return a new list, use the sorted() built-in function...
newlist = sorted(ut, key=lambda x: x.count, reverse=True)

কী অনুসারে বাছাই করার বিষয়ে আরও কিছু ।


1
সমস্যা নেই. বিটিডব্লিউ, যদি মুহুক ঠিক থাকে এবং এটি জ্যাঙ্গো অবজেক্টগুলির একটি তালিকা থাকে তবে আপনার সমাধানটি বিবেচনা করা উচিত। যাইহোক, বাছাই করা সামগ্রীর সাধারণ ক্ষেত্রে, আমার সমাধান সম্ভবত সেরা অনুশীলন।
ট্রিপটিচ

43
বড় তালিকাগুলিতে আপনি অপারেটর.আউটটারজেটার ('কাউন্ট') আপনার কী হিসাবে ব্যবহার করে আরও ভাল পারফরম্যান্স পাবেন। এই উত্তরের ল্যাম্বদা ফাংশনের এটি কেবলমাত্র একটি অনুকূলিত (নিম্ন স্তরের) ফর্ম।
ডেভিড আইক

4
দুর্দান্ত উত্তরের জন্য ধন্যবাদ। যদি এটি অভিধানের একটি তালিকা হয় এবং 'গণনা' এর কীগুলির মধ্যে একটি হয় তবে এটি নীচের মত বদলাতে হবে: ut.sort (কী = ল্যাম্বদা এক্স: এক্স ['গণনা'], বিপরীত = সত্য)
dganesh2002

আমি মনে করি এটি নিম্নলিখিত আপডেটের প্রাপ্য: যদি একাধিক ক্ষেত্র অনুসারে বাছাই করার প্রয়োজন হয় তবে এটি ক্রমাগত কলগুলি () সাজানোর জন্য অর্জন করা যেতে পারে, কারণ পাইথন স্থিতিশীল বাছাই অ্যালগরিদম ব্যবহার করছে।
zzz777

86

একটি উপায় যা দ্রুততম হতে পারে, বিশেষত যদি আপনার তালিকায় প্রচুর রেকর্ড থাকে তবে তা ব্যবহার করা হয় operator.attrgetter("count")। তবে এটি পাইথনের প্রাক অপারেটর সংস্করণে চলতে পারে, সুতরাং ফ্যালব্যাক প্রক্রিয়াটি ভাল লাগবে। আপনি নিম্নলিখিতগুলি করতে পারেন, তারপরে:

try: import operator
except ImportError: keyfun= lambda x: x.count # use a lambda if no operator module
else: keyfun= operator.attrgetter("count") # use operator since it's faster than lambda

ut.sort(key=keyfun, reverse=True) # sort in-place

7
এখানে আমি বিভ্রান্তি এড়াতে "cmpfun" পরিবর্তে "কীফান" পরিবর্তনশীল নামটি ব্যবহার করব। সাজানো () পদ্ধতিটি সিএমপি = যুক্তির মাধ্যমেও একটি তুলনা ফাংশন গ্রহণ করে accept
আকাইহোলা

যদি বস্তুটি গতিশীল বৈশিষ্ট্য যুক্ত করেছে, (আপনি যদি পদ্ধতিটির self.__dict__ = {'some':'dict'}পরে কাজটি করেন __init__) তবে এটি কাজ করে না বলে মনে হচ্ছে । যদিও কেন এটি আলাদা হয় কেন জানি না।
tutuca

@ টুটুকা: আমি উদাহরণটি কখনও প্রতিস্থাপন করিনি __dict__। নোট করুন যে "একটি বস্তু গতিশীল যুক্ত বৈশিষ্ট্য যুক্ত" এবং "একটি অবজেক্টের __dict__বৈশিষ্ট্য নির্ধারণ" প্রায় অর্থেগোনাল ধারণা। আমি বলছি যেহেতু আপনার মন্তব্যটি থেকে বোঝা যাচ্ছে যে __dict__গুনগতভাবে অ্যাট্রিবিউট যুক্ত করার জন্য বৈশিষ্ট্যটি নির্ধারণ করা প্রয়োজনীয় a
tzot

@ টজোট: আমি এখানে ঠিকই দেখছি: github.com/stochastic-technologies/goatfish/blob/master/… এবং সেই পুনরুক্তিটি এখানে ব্যবহার করছি: github.com/TallerT Technology / dishey / blob / master / app.py#L28 উত্থাপন বৈশিষ্ট্য ত্রুটি পাইথন 3 এর কারণে হতে পারে তবে তবুও ...
tutuca

1
@ টজোট: আমি যদি এর ব্যবহার বুঝতে পারি তবে আমি operator.attrgetterকোনও সম্পত্তির নাম সহ একটি ফাংশন সরবরাহ করতে এবং একটি সাজানো সংগ্রহ ফিরিয়ে দিতে পারি।
আইএবস্ট্র্যাক্ট

64

পাঠকদের লক্ষ্য করা উচিত যে কী = পদ্ধতি:

ut.sort(key=lambda x: x.count, reverse=True)

বস্তুগুলিতে সমৃদ্ধ তুলনা অপারেটর যুক্ত করার চেয়ে অনেকগুণ দ্রুত। আমি এটি পড়তে অবাক হয়েছিলাম ("সংক্ষেপে পাইথন ইন 485 পৃষ্ঠা")। এই ছোট প্রোগ্রামটিতে পরীক্ষা চালিয়ে আপনি এটি নিশ্চিত করতে পারেন:

#!/usr/bin/env python
import random

class C:
    def __init__(self,count):
        self.count = count

    def __cmp__(self,other):
        return cmp(self.count,other.count)

longList = [C(random.random()) for i in xrange(1000000)] #about 6.1 secs
longList2 = longList[:]

longList.sort() #about 52 - 6.1 = 46 secs
longList2.sort(key = lambda c: c.count) #about 9 - 6.1 = 3 secs

আমার, খুব ন্যূনতম, পরীক্ষাগুলি দেখায় যে প্রথম ক্রমটি 10 ​​গুণ বেশি ধীর হয় তবে বইটি বলে যে এটি সাধারণভাবে প্রায় 5 গুণ ধীর। তারা বলার কারণটি পাইথনের ( টিমসোর্ট ) ব্যবহৃত সর্বাধিকরূপে সাজানো অ্যালগরিদম m

তবুও, এর খুব অদ্ভুত যে। সর্ট (ল্যাম্বডা) সরল পুরাতন .সোস্ট () এর চেয়ে দ্রুত। আমি আশা করি তারা এটি ঠিক করে দিয়েছেন।


1
সংজ্ঞা __cmp__কল করার সমতুল্য , তাই .sort(cmp=lambda)নয় .sort(key=lambda), এটি মোটেও বিজোড় নয়।
tzot

@tzot ঠিক ঠিক। প্রথম সাজানোর ক্ষেত্রে একে অপরের বিরুদ্ধে বারবার তুলনা করতে হয়। দ্বিতীয় সাজানোর মাধ্যমে প্রতিটি বস্তুকে তার গণনা মানটি বের করার জন্য একবার একবার অ্যাক্সেস করে এবং তারপরে এটি একটি সাধারণ সংখ্যাসমূহ বাছাই করে যা অত্যন্ত অনুকূলিত হয়। আরও ন্যায্য তুলনা হবে longList2.sort(cmp = cmp)। আমি এটি চেষ্টা করেছিলাম এবং এটি প্রায় একই রকম সম্পাদন করে .sort()। (এছাড়াও: দ্রষ্টব্য যে পাইথন 3-তে "সিএমপি" বাছাই প্যারামিটারটি সরানো হয়েছিল))
ব্রায়ান রোচ

43

অবজেক্ট-ওরিয়েন্টেড অ্যাপ্রোচ

অর্ডারের প্রয়োজনীয়তা প্রতিটি ক্ষেত্রে অন্তর্ভুক্ত করার পরিবর্তে শ্রেণীর একটি সম্পত্তি যুক্ত করার জন্য অবজেক্ট বাছাইয়ের যুক্তি তৈরি করা ভাল অনুশীলন make

এটি ধারাবাহিকতা নিশ্চিত করে এবং বয়লারপ্লেট কোডের প্রয়োজনীয়তা সরিয়ে দেয়।

সর্বনিম্ন, আপনার এটি নির্দিষ্ট করতে __eq__এবং __lt__কাজ করতে অপারেশন করা উচিত । তারপরে শুধু ব্যবহার করুন sorted(list_of_objects)

class Card(object):

    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __eq__(self, other):
        return self.rank == other.rank and self.suit == other.suit

    def __lt__(self, other):
        return self.rank < other.rank

hand = [Card(10, 'H'), Card(2, 'h'), Card(12, 'h'), Card(13, 'h'), Card(14, 'h')]
hand_order = [c.rank for c in hand]  # [10, 2, 12, 13, 14]

hand_sorted = sorted(hand)
hand_sorted_order = [c.rank for c in hand_sorted]  # [2, 10, 12, 13, 14]

1
এটাই আমি খুঁজছিলাম! আপনি কি আমাদের এমন কিছু ডকুমেন্টেশনের দিকে নির্দেশ করতে পারেন যা সর্বনিম্ন বাস্তবায়নের প্রয়োজনীয়তা কেন __eq__এবং __lt__এর উপর বিস্তারিত রয়েছে ?
ফ্রেন্ডএফএক্স

1
@FriendFX, আমি বিশ্বাস করি ক্ষেত্রে প্রযোজ্য হচ্ছে এই :•The sort routines are guaranteed to use __lt__() when making comparisons between two objects...
jpp

2
@ ফ্রেন্ডএফএক্স: তুলনা ও বাছাইয়ের জন্য Portingguide.readthedocs.io/en/latest/comparisons.html দেখুন
কর্নেল ম্যাসন

37
from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)

16

এটি দেখতে অনেকটা জ্যাঙ্গো ওআরএম মডেল উদাহরণগুলির তালিকার মতো like

এগুলি কেন কোয়েরিতে তাদের সাজান না:

ut = Tag.objects.order_by('-count')

এটি, তবে জাঙ্গো-ট্যাগিং ব্যবহার করে, তাই আমি নির্দিষ্ট কোয়েরি সেটগুলির জন্য ব্যবহার করে একটি ট্যাগ সেট দখল করার জন্য একটি বিল্ট-ইন ব্যবহার করছিলাম, যেমন: Tag.objects.usage_for_queryset (ক্যোয়ারীসেট, গণনা = সত্য)
নিক সার্জেন্ট

11

অবজেক্ট ক্লাসে সমৃদ্ধ তুলনা অপারেটর যুক্ত করুন, তারপরে তালিকার ক্রম () পদ্ধতিটি ব্যবহার করুন। পাইথনে সমৃদ্ধ তুলনা
দেখুন ।


আপডেট : যদিও এই পদ্ধতিটি কার্যকর হবে, তবুও আমি মনে করি ট্রাইপটাইকের কাছ থেকে সমাধান আপনার ক্ষেত্রে উপযুক্ত suited


3

আপনি যে বৈশিষ্ট্যটি অনুসারে বাছাই করতে চান তা যদি কোনও সম্পত্তি হয় তবে আপনি operator.attrgetterতার fgetপরিবর্তে সম্পত্তিটির পদ্ধতি আমদানি করতে এবং ব্যবহার করতে পারেন ।

উদাহরণস্বরূপ, Circleএকটি সম্পত্তি সহ একটি শ্রেণীর জন্য radiusআমরা circlesরেডিয়ির দ্বারা নিম্নরূপ একটি তালিকা বাছাই করতে পারি :

result = sorted(circles, key=Circle.radius.fget)

এটি সর্বাধিক সুপরিচিত বৈশিষ্ট্য নয় তবে প্রায়শই আমদানি সহ আমাকে একটি লাইন সংরক্ষণ করে।

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