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




sorting dictionary (20)

اعتبارًا من Python 3.6 ، سيتم طلب الأمر المدمج

الخبر السار ، وبالتالي فإن حالة الاستخدام الأصلية لأزواج الخرائط المسترجعة من قاعدة بيانات تحتوي على معرفات سلسلة فريدة كمفاتيح وقيم رقمية كقيم في مضمن بيثون v3.6 + مدمج ، يجب أن تحترم الآن ترتيب الإدراج.

إذا قل تعبيرات جدول الأعمدة الناتجة عن استعلام قاعدة بيانات مثل:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

سيتم تخزينها في مجموعتي بايثون ، k_seq و v_seq (تتم محاذاتها بواسطة فهرس رقمي وبنفس طول الدورة التدريبية) ، ثم:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

السماح بالإنتاج لاحقًا على النحو التالي:

for k, v in ordered_map.items():
    print(k, v)

العائد في هذه الحالة (لبيثون الجديدة 3.6 + المدمج في!):

foo 0
bar 1
baz 42

في نفس الترتيب لكل قيمة v.

في مكان تثبيت Python 3.5 على جهازي ، ينتج حاليًا ما يلي:

bar 1
foo 0
baz 42

تفاصيل:

كما اقترح في عام 2012 من قبل ريموند هتينجر (راجع بريد على python-dev مع الموضوع "قواميس أكثر اتقانا مع التكرار الأسرع" ) والآن (في عام 2016) أعلن في رسالة بريدية من قبل فيكتور ستينر إلى python-dev مع الموضوع "يصبح python 3.6 dict مضغوط ويحصل على إصدار خاص ؛ والكلمات الرئيسية تصبح أمرًا " نظرًا لإصلاح / تنفيذ المشكلة 27350 " الإملاء المضغوط والنظام " في Python 3.6 ، سنكون الآن قادرين على استخدام أداة مدمجة للحفاظ على أمر الإدراج !!

نأمل أن يؤدي هذا إلى تطبيق طبقة رقيقة OrderedDict كخطوة أولى. وكما أشار إليه @ JimFasarakis-Hilliard ، يرى البعض حالات استخدام لنوع OrderedDict أيضًا في المستقبل. أعتقد أن مجتمع بايثون سيتفحصون بعناية ، إذا كان ذلك سيحمل اختبار الزمن ، وما هي الخطوات التالية.

حان الوقت لإعادة التفكير في عادات الترميز الخاصة بنا لكي لا تفوتك الإمكانيات التي تفتحها الطلبات المستقرة من:

  • وسيطات الكلمات الرئيسية و
  • (متوسطة) تخزين dict

الأول لأنه يسهل إيفاد في تنفيذ المهام والأساليب في بعض الحالات.

والثاني كما يشجع على استخدام بسهولة أكبر كما التخزين وسيطة في خطوط الأنابيب المعالجة.

قام ريمون هيتينغر بتقديم وثائق تشرح " The Tech Behind Python 3.6 Dictionaries " - من عرضه التقديمي لمجموعة سان فرانسيسكو بايثون 2016-DEC-08.

وربما بعض صفحات الأسئلة والأجوبة المصممة بشكل عالي من Stack Overflow ستتلقى تنويعات من هذه المعلومات وستتطلب العديد من الإجابات ذات الجودة العالية تحديثًا لكل إصدار أيضًا.

التحذير Emptor (ولكن انظر أيضا أدناه التحديث 2017/12/12):

كما يلاحظajcr بشكل صحيح: "يعتبر جانب الحفاظ على النظام في هذا التنفيذ الجديد تفصيليًا للتنفيذ ويجب عدم الاعتماد عليه." (من whatsnew36 ) لا اختيار أحمق ، ولكن تم قطع الاقتباس متشائم قليلا ؛-). ويستمر الأمر "(قد يتغير هذا في المستقبل ، ولكن من المرجّح أن يتم تنفيذ هذا التطبيق الجديد في اللغة لعدد قليل من الإصدارات قبل تغيير مواصفات اللغة لفرض دلالات الحفاظ على النظام لجميع تطبيقات بايثون الحالية والمستقبلية ؛ وهذا أيضًا يساعد على الحفاظ على التوافق مع الإصدارات القديمة من اللغة حيث لا يزال ترتيب التكرار العشوائي ساري المفعول ، على سبيل المثال Python 3.5). "

كما هو الحال في بعض اللغات البشرية (مثل اللغة الألمانية) ، فإن الاستخدام يشكل اللغة ، وسيتم الإعلان عن الإرادة الآن ... في whatsnew36 .

التحديث 2017-12-15:

في بريد إلى قائمة python-dev ، أعلن Guido van Rossum:

اجعلها كذلك. "Dict تبقي أمر الإدراج" هو الحكم. شكر!

لذلك ، أصبح الإصدار الثالث من CPython من التأثير الجانبي لترتيب إدخال الأوامر جزءًا من مواصفات اللغة (وليس فقط بعد ذلك تفاصيل التنفيذ). هذا الخيط البريدى ظهر أيضا بعض أهداف التصميم المميزة collections.OrderedDict أمرت كما ذكره ريموند هتينجر أثناء المناقشة.

https://code.i-harness.com

لدي قاموس من القيم يقرأ من حقلين في قاعدة بيانات: حقل سلسلة وحقل رقمي. يعتبر حقل السلسلة فريدًا ، لذا فهو مفتاح القاموس.

يمكنني الفرز على المفاتيح ، ولكن كيف يمكنني الترتيب حسب القيم؟

ملاحظة: لقد قرأت سؤال Stack Overflow كيف يمكنني فرز قائمة القواميس حسب قيم القاموس في Python؟ وربما يمكن أن أغير الكود الخاص بي لكي يكون لدي قائمة من القواميس ، ولكن بما أنني لا أحتاج حقاً إلى قائمة من القواميس أردت معرفة ما إذا كان هناك حل أبسط.


بسيطة مثل: sorted(dict1, key=dict1.get)

حسنًا ، من الممكن فعلًا إجراء "فرز حسب قيم القاموس". في الآونة الأخيرة اضطررت إلى القيام بذلك في لعبة غولف جولف ( question Code golf: Word Frequency Chart ). مختصرة ، كانت المشكلة من النوع: في ضوء النص ، احسب عدد المرات التي تتم فيها مصادفة كل كلمة وعرض قائمة من أهم الكلمات ، مرتبة حسب تناقص التردد.

إذا قمت بإنشاء قاموس بالكلمات كمفاتيح وعدد مرات ظهور كل كلمة كقيمة ، فيتم تبسيطها هنا على النحو التالي:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
  d[w] += 1

ثم يمكنك الحصول على قائمة بالكلمات ، مرتبة حسب تكرار الاستخدام مع sorted(d, key=d.get) - يتم sorted(d, key=d.get) الفرز فوق مفاتيح القاموس ، باستخدام عدد مرات ظهور الكلمة كمفتاح فرز.

for w in sorted(d, key=d.get, reverse=True):
  print w, d[w]

أكتب إليكم هذا الشرح التفصيلي لتوضيح ما يعنيه الناس في كثير من الأحيان من خلال "يمكنني بسهولة فرز القاموس عن طريق المفتاح ، ولكن كيف يمكنني الترتيب حسب القيمة" - وأعتقد أن البروتوكول الاختياري كان يحاول معالجة مثل هذه القضية. والحل هو القيام بنوع من قائمة المفاتيح ، استنادًا إلى القيم ، كما هو موضح أعلاه.


إلى حد كبير نفس إجابة هانك غاي.

    sorted([(value,key) for (key,value) in mydict.items()])

أو الأمثل قليلا كما اقترح جون فوهي.

    sorted((value,key) for (key,value) in mydict.items())


استخدم ValueSortedDict من dicts :

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

بالطبع ، تذكر ، تحتاج إلى استخدام OrderedDict لأن قواميس Python العادية لا تحتفظ بالترتيب الأصلي.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key = lambda x: x[1]))

إذا لم يكن لديك Python 2.7 أو أعلى ، فإن أفضل ما يمكنك القيام به هو التكرار على القيم في وظيفة المولد. (هناك أمر OrderedDict لـ 2.4 و 2.6 here ، لكن

a) I don't know about how well it works 

و

b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option's out.)
def gen(originalDict):
    for x,y in sorted(zip(originalDict.keys(), originalDict.values()), key = lambda z: z[1]):
        yield (x, y)
    #Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])

يمكنك أيضًا طباعة كل قيمة

for bleh, meh in gen(myDict):
    print(bleh,meh)

يرجى تذكر إزالة الأقواس بعد الطباعة إن لم تكن تستخدم Python 3.0 أو أعلى


جرب الطريقة التالية. دعونا تحديد قاموس يسمى mydict مع البيانات التالية:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

إذا أراد المرء ترتيب المعجم باستخدام مفاتيح ، فيمكن أن يفعل المرء شيئًا مثل:

for key in sorted(mydict.iterkeys()):
    print "%s: %s" % (key, mydict[key])

هذا يجب إرجاع الإخراج التالي:

alan: 2
bob: 1
carl: 40
danny: 3

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

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

يجب أن ترجع نتيجة هذا الأمر (فرز القاموس حسب القيمة) إلى ما يلي:

bob: 1
alan: 2
danny: 3
carl: 40

في Python 2.7 الحديثة ، لدينا نوع OrderedDict الجديد ، الذي يتذكر ترتيب إضافة العناصر.

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

لإنشاء قاموس مرتب جديد من النص الأصلي ، وفرز حسب القيم:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

يتصرف OrderedDict مثل dict عادي:

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])

لا يمكن فرز Dicts ، ولكن يمكنك إنشاء قائمة مرتبة منها.

قائمة مرتبة لقيم dict:

sorted(d.values())

قائمة من أزواج (مفتاح ، قيمة) ، مرتبة حسب القيمة:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))

لقد توصلت إلى هذا ،

import operator    
x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_x = {k[0]:k[1] for k in sorted(x.items(), key=operator.itemgetter(1))}

لـ Python 3.x: x.items() استبدال iteritems() .

>>> sorted_x
{0: 0, 1: 2, 2: 1, 3: 4, 4: 3}

أو حاول مع collections.OrderedDict

x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
from collections import OrderedDict

od1 = OrderedDict(sorted(x.items(), key=lambda t: t[1]))

من الناحية الفنية ، القواميس ليست متتالية ، وبالتالي لا يمكن فرزها. يمكنك أن تفعل شيء من هذا القبيل

sorted(a_dictionary.values())

افتراض الأداء ليس صفقة كبيرة.


هنا هو الحل باستخدام الرمز البريدي على d.values() و d.keys() . هناك بضعة أسطر أسفل هذا الارتباط (في كائنات عرض القاموس):

هذا يسمح بإنشاء أزواج (قيمة ، مفتاح) باستخدام zip (): pairs = zip (d.values ​​()، d.keys ()).

حتى نتمكن من القيام بما يلي:

d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}

d_sorted = sorted(zip(d.values(), d.keys()))

print d_sorted 
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]

واجهت نفس المشكلة ، وحلت الأمر على هذا النحو:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(الأشخاص الذين أجابوا "ليس من الممكن فرز الامل" لم يقرأوا السؤال! في الواقع ، "يمكنني الفرز على المفاتيح ، ولكن كيف يمكنني الفرز على أساس القيم؟" يعني بوضوح أنه يريد قائمة مفاتيح فرزها حسب قيمة قيمها.)

يرجى ملاحظة أن الأمر غير محدد بشكل جيد (المفاتيح ذات القيمة نفسها ستكون بترتيب تعسفي في قائمة المخرجات).


يتكرر من خلال dict وترتيبها حسب قيمها بترتيب تنازلي:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1

يمكن أن يكون في كثير من الأحيان مفيد جدا لاستخدام namedtuple . على سبيل المثال ، لديك قاموس 'name' كمفاتيح و 'score' كقيم وتريد الفرز على 'score':

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

الفرز بأقل درجة أولاً:

worst = sorted(Player(v,k) for (k,v) in d.items())

الفرز مع أعلى الدرجات أولاً:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

الآن يمكنك الحصول على الاسم والنتيجة ، دعنا نقول ثاني أفضل لاعب (index = 1) جدا Pythonically مثل:

player = best[1]
player.name
    'Richard'
player.score
    7

يمكنك إنشاء "فهرس مقلوب" أيضًا

from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

الآن معكوس يحتوي على القيم؛ كل قيمة لديها قائمة من المفاتيح المعمول بها.

for k in sorted(inverse):
    print k, inverse[k]

يمكنك استخدام collections.Counter . لاحظ أن هذا سيعمل على القيم الرقمية وغير الرقمية.

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

يمكنك استخدام وظيفة بيثون المصنفة

sorted(iterable[, cmp[, key[, reverse]]])

وبالتالي يمكنك استخدام:

sorted(dictionary.items(),key = lambda x :x[1])

تفضل بزيارة هذا الرابط لمزيد من المعلومات حول الوظيفة المصنفة: https://docs.python.org/2/library/functions.html#sorted


يمكنك استخدام:

sorted(d.items(), key=lambda x: x[1])

سيؤدي ذلك إلى فرز القاموس حسب قيم كل إدخال داخل القاموس من الأصغر إلى الأكبر.


كما أشار Dilettant ، سوف تحتفظ Python 3.6 الآن ! ظننت أنني أشارك وظيفة كتبتها تخفف من فرز (tuple، list، dict). في الحالة الأخيرة ، يمكنك الفرز إما على المفاتيح أو القيم ، ويمكن أن تأخذ المقارنة الرقمية في الاعتبار. فقط من أجل> = 3.6!

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

تعليقات للتحسين أو طلبات الدفع موضع ترحيب.

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))

      return _sorted

    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    elif isinstance(iterable, tuple):
      sorted_list = tuple(_sort(None))
      return sorted_list
    elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")

إذا كانت قيمك أعداد صحيحة ، وكنت تستخدم Python 2.7 أو أحدث ، فيمكنك استخدام collections.Counterبدلاً من dict. و most_commonسوف طريقة أعطيك كل البنود، مرتبة حسب القيمة.





dictionary