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




sorting dictionary (25)

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

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

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


Answers

هنا هو الحل باستخدام الرمز البريدي على 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')]

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

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

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

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

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


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

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

sorted(d.values())

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

from operator import itemgetter
sorted(d.items(), key=itemgetter(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")

هذا هو الكود:

import operator
origin_list = [
    {"name": "foo", "rank": 0, "rofl": 20000},
    {"name": "Silly", "rank": 15, "rofl": 1000},
    {"name": "Baa", "rank": 300, "rofl": 20},
    {"name": "Zoo", "rank": 10, "rofl": 200},
    {"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in origin_list:
    print foo

print "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo

وهنا النتائج:

أصلي

{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

روفل

{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

مرتبة

{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}

بسيطة مثل: 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]

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


from django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict

يتكرر من خلال 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

بالطبع ، تذكر ، تحتاج إلى استخدام 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 أو أعلى


إذا كانت القيم رقمية ، يمكنك أيضًا استخدام العداد من المجموعات

from collections import Counter

x={'hello':1,'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]    

يمكنك أيضًا استخدام وظيفة مخصصة يمكن تمريرها إلى المفتاح.

def dict_val(x):
    return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)

طريقة واحدة أخرى للقيام به هو استخدام وظيفة labmda

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda t: t[1])

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

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

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


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

sorted(a_dictionary.values())

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


اعتبارًا من 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.

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

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

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

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

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

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

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

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


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

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

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

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


في 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)])

في Python 2.7 ، ببساطة قم بما يلي:

from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

نسخ ولصق من: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

استمتع ؛-)


المعطى المعطى

e = {1:39, 4:34, 7:110, 2:87}

فرز

sred = sorted(e.items(), key=lambda value: value[1])

نتيجة

[(4, 34), (1, 39), (2, 87), (7, 110)]

يمكنك استخدام دالة lambda لفرز الأشياء حسب القيمة وتخزينها معالجتها داخل متغير ، في هذه الحالة مع e القاموس الأصلي.

امل ان يساعد!


يمكنك استخدام 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)])

يمكنك استخدام عبارة تخطي عبارة عن قاموس يتم فرزه حسب القيمة بشكل دائم.

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

إذا كنت تستخدم keys() ، أو values() أو items() فستتكرر في ترتيب تم فرزه حسب القيمة.

يتم تنفيذه باستخدام قاعدة بيانات قائمة التخطي.


يؤدي هذا إلى إرجاع قائمة أزواج القيم الأساسية في القاموس ، مرتبة حسب القيمة من الأعلى إلى الأقل:

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

للحصول على القاموس الذي تم فرزه حسب المفتاح ، استخدم ما يلي:

sorted(d.items(), reverse=True)

تمثل هذه العودة قائمة من المجموعات لأن القواميس نفسها لا يمكن تصنيفها.

يمكن طباعة هذا الأمر أو إرساله إلى حساب آخر.


استخدم 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)]

لا يمكن فرز قاموس ، فقط للحصول على تمثيل لقاموس يتم فرزه. القواميس بطبيعتها غير مرتب ، لكن أنواع أخرى ، مثل القوائم و tuples ، ليست كذلك. لذلك تحتاج إلى نوع بيانات مُرَشَّح لتمثيل القيم التي تم فرزها ، والتي ستكون قائمة - من المحتمل أن تكون قائمة من المجموعات.

على سبيل المثال،

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

ستكون sorted_x قائمة من المجموعات التي تم فرزها حسب العنصر الثاني في كل مجموعة. dict(sorted_x) == x .

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

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

في Python3 نظرًا لأنه غير مسموح بفك الشفرة [1] يمكننا استخدامه

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_by_value = sorted(x.items(), key=lambda kv: kv[1])

تحديث: 5 ديسمبر 2015 باستخدام Python 3.5

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

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

تقدم وثائق OrderedDict الرسمية مثالًا مشابهًا جدًا أيضًا ، ولكن باستخدام دالة lambda للفرز:

# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

ليس عليك استدعاء مفاتيح:

if 'key1' in dict:
  print "blah"
else:
  print "boo"

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





python sorting dictionary