Woordenboeken sorteren op sleutels in Python

Kan iemand me vertellen hoe ik dit kan sorteren:

{'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}

in

{'a': [1, 2, 3], 'b': ['blah', 'bhasdf', 'asdf'], 'c': ['one', 'two'],'d': ['asdf', 'wer', 'asdf', 'zxcv']}

?
Bedankt!

UPDATE 1, codevoorbeeld:

Dus ik doe taalkunde. Eén artikel is opgesplitst in woorden die zijn opgeslagen in een database en allerlei eigenschappen hebben, waaronder para-ID en zin-ID. De taak: proberen de originele tekst opnieuw op te bouwen.

Haal 500 opeenvolgende woorden uit DB

words = Words.objects.all()[wordId:wordId+500]
# I first create paragraphs, through which I can loop later in my django template,
# and in each para will be a list of words (also dictionaries). 
# So i am trying to get a dictionary with values that are lists of dictionaries. 
# 'pp' i make just for shorthanding a long-named variable.
paras={}
para_high = para_low =  words[0].belongs_to_paragraph
for w in words:
    last_word = w
    pp = w.belongs_to_paragraph
    if pp >para_high:
        para_high = pp
    if pp < para_low:
        para_low = pp
    if pp in paras:
        paras[pp].append(w)
    else:
        list = [w]
        paras[pp] = list
# Since there are blank lines between paragraphs, in rebuilding the text as it 
    #  looked originally, I need to insert blank lines. 
    # Since i have the ID's of the paragraphs and they go somewhat like that: 1,3,4,8,9 
    #(the gaps between 1 & 3 and 4 & 8 i have to fill in with something else, 
    # which is why i had para_low and para_high to loop the range. 
isbr = True
for i in range(para_low, para_high+1):
    if i in paras:
        isbr = True
    else:
        if isbr:
            paras[i]=['break']
            isbr = False
        else:
            paras[i]=[]

Op dit punt echter, als ik de dict probeert te lussen en de tekst opnieuw op te bouwen, komen enkele latere ID’D-paragrafen vóór vorige, en dat doet het gewoon niet.

Update 2, luscode:

       {% for k,v in wording.iteritems()  %}
        {% if v[0] == 'break' %}
        <br/>
        {% else %}
        </div><div class="p">{% for word in v %}{% if word.special==0%} {% endif %}<span class="word {% if word.special == 0%}clickable{% endif%}" wid="{{word.id}}" special="{{word.special}}" somethingElse={{word.somethingElse}}>{{ word.word }}</span>{% endfor %}
        {% endif %}
    {% endfor %}

Antwoord 1, Autoriteit 100%

Dictten hebben geen bestelling.

U kunt gesorteerd zijn, maar dit geeft u een geselecteerde lijst van de toetsen:

>>> sorted(d)
['a', 'b', 'c', 'd']

U kunt het behandelen als een iespunt en sorteer de sleutelwaarde-tuples, maar dan heb je net een lijst met tuples. Dat is niet hetzelfde als een dict.

>>> sorted(d.items())
[
 ('a', [1, 2, 3]),
 ('b', ['blah', 'bhasdf', 'asdf']),
 ('c', ['one', 'two']),
 ('d', ['asdf', 'wer', 'asdf', 'zxcv'])
]

Als u Python 2.7 of nieuwer gebruikt, kunt u ook overwegen een te gebruiken OrderedDict.

dict-subklasse die onthoudt dat de orderinvoer is toegevoegd

Bijvoorbeeld:

>>> d = collections.OrderedDict(sorted(d.items()))
>>> for k, v in d.items():
>>>     print k, v
a [1, 2, 3]
b ['blah', 'bhasdf', 'asdf']
c ['een', 'twee']
d ['asdf', 'wer', 'asdf', 'zxcv']

Antwoord 2, autoriteit 65%

Het juisteantwoord is dat als je de items van een woordenboek in een gesorteerde volgorde wilt hebben, je de functie sort() moet gebruiken wanneer je het woordenboek doorloopt:

for k, v in sorted(d.items()):
    print k, ':', v

of

for k in sorted(d):
   print d[k]

Of vergelijkbaar.

Het genoemde OrderedDict is voor woordenboeken met een volgorde. En bestellen is niet hetzelfde als sorteren. Je kunt een gesorteerde OrderedDict maken, ja, maar zodra je een nieuwe sleutel toevoegt, wordt deze niet meer gesorteerd. Dus je zou toch gesorteerd() moeten gebruikenom het voor elk gebruik of na elke manipulatie te sorteren. De OrderedDict is daarom alleen langzamer en geheugenintensiever dan een gewoon woordenboek, terwijl het niets toevoegt wat je nodig hebt.

OrderedDict zijn nietvoor gesorteerde woordenboeken, maar voor woordenboeken waar de items een soort volgorde hebben die geensortering is. Bijvoorbeeld als je dingen wilt laten zien in de volgorde waarin ze zijn toegevoegd, of als je wilt dat gebruikers dingen willekeurig kunnen bestellen.

Update: Verdere uitleg

Waarom is OrderedDict geen oplossing? Omdat een OrderedDict wordt geordendniet gesorteerd.

Overweeg een standaardwoordenboek:

>>> d = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}

Het is niet gesorteerd, zoals we hieronder zien, komt ‘c’ voor ‘b’. Het heeft ook geen volgorde, als we nieuwe dingen toevoegen, lijkt het op een willekeurige volgorde:

>>> d['g'] = 6
>>> d['i'] = 8
>>> d
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8}

OK, laten we dan een OrderedDict gebruiken:

>>> o = OrderedDict(sorted({'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}.items()))
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5)])

Aha! Gesorteerd! Dus OrderedDict werkt!? Nee.

>>> o['i'] = 8
>>> o['g'] = 6
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('i', 8), ('g', 6)])

Wat? De g eindigde nade i?!? Waarom!? Omdat de OrderedDict niet is gesorteerd, is deze geordend. Het onthoudt de volgordewaarin je dingen toevoegt. Niet de sortering. Dit betekent dat u het elke keer dat u het gebruikt, eerst moet sorteren. Een OrderedDict blijft alleen gesorteerd zolang u er geen sleutels aan toevoegt. Maar als je het niet gaat wijzigen, heb je geen dictaat nodig. Je kunt net zo goed een lijst hebben. Wat krijg je van gesorteerd():

>>> sorted(o.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

Maar dat werkt net zo goed met het standaardwoordenboek, dus de OrderedDictionary hielp niet:

>>> sorted(d.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

Conclusie
Dus elke keer dat u het woordenboek op een gesorteerde manier wilt doorlopen, moet u het volgende doen:

>>> for k in sorted(o):
...   print k, o[k]
... 
a 0
b 1
c 2
d 3
e 4
f 5
g 6
i 8

En dat is het maakt niet uit welk woordenboek je gebruikt. OrderedDict helpt je niet echt, omdat het niet om sorterengaat, alleen om de volgordewaarin je dingen toevoegt.


Antwoord 3, autoriteit 10%

Het is vermeldenswaard dat Python een aantal woordenboekimplementaties heeft die de sleutels in gesorteerde volgorde houden. Overweeg de module sortedcontainersdie pure Python- en fast-as-C-implementaties zijn. Er is een prestatievergelijkingmet andere snelle en feature-complete implementaties die tegen elkaar zijn gebenchmarkt.

Bijvoorbeeld:

>>> from sortedcontainers import SortedDict
>>> d = {'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}
>>> s = SortedDict(**d)
>>> s.keys()
SortedSet(['a', 'b', 'c', 'd'])

U kunt uw gebruik van dictaat ook volledig vervangen door SortedDictaangezien het snelle bewerkingen voor ophalen/instellen en gesorteerde iteraties van items op toets.


Antwoord 4, autoriteit 2%

Zoals het andere antwoord al zei, is de volgorde van de sleutels van een woordenboek willekeurig en moet u er niet op vertrouwen.

Als je Python 2.7 of 3.1 of hoger gebruikt, probeer dan collections.OrderedDict(2.7 documenten; 3.1 docs; zie ook PEP 372). Er is een link in de documenten naar een pure-Python-versie van OrderedDictdie werkt op eerdere Python-versies .


Antwoord 5, autoriteit 2%

Hier is een snelle en gemakkelijke functie die u kunt gebruiken om een woordenboek op sleutels te sorteren.

Zet deze code in een apart bestand met de naam sdict.py:

def sortdict(dct):
    kys = dct.keys()
    kys.sort()
    from collections import OrderedDict
    d = OrderedDict()
    for x in kys: 
        for k, v in dct.iteritems():
            if (k == x):
                d[k] = v
    return d

Plaats deze code nu in een apart bestand met de naam test.pyom het te testen met een voorbeeldwoordenboek:

from sdict import sortdict
import json
dct = {'sizes':[32,28,42], 'dog':'schnauser', 'cat':'siamese', 'bird':'falcon'}
dctx = sortdict(dct)
print json.dumps(dctx) 

En tot slot, bel test.pyvanaf de opdrachtregel:

$ python test.py
{"bird": "falcon", "cat": "siamese", "dog": "schnauser", "sizes": [32, 28, 42]}

Ik gebruik alleen de json.dumps-regel om je te laten zien dat het een echt woordenboek is en niet alleen een tekenreeksrepresentatie. Je kunt het trouwens ook testen met de type() functie.

Ik heb een geneste lijst met numerieke waarden in het voorbeeldwoordenboek opgenomen om te laten zien dat de functie complexere woordenboeken aankan, niet alleen op strings gebaseerde dictaten met één laag.

De code is vrij eenvoudig, dus het zou gemakkelijk zijn om deze aan te passen om op waarden te sorteren, als dat uw voorkeur is – hoewel sorteren op waarde geen zin zou hebben als sommige waarden objecten zijn, zoals lijsten, tupels of andere dicts .

Toegegeven, dit werkt alleen in python 2.7 of hoger.

Proficiat,
-=Cameron


Antwoord 6

Het is misschien ook de moeite waard om de grootste routine in heapq te noemen. Dit sorteert en retourneert de top N items. Afhankelijk van wat er werkelijk nodig is, kan dit handig zijn als u met de sleutelparameter speelt. Ik vermeld dit vooral sinds ik het een paar nachten geleden ontdekte en het deed precies wat ik zocht. Zie PEP 0265en Heapq.


Antwoord 7

Ik zal mijn cent toevoegen aan wat anderen al hebben uitgelegd. Ik had toevallig precies hetzelfde probleem in een specifiek geval. Ik wilde dat de uitvoer van mijn woordenboek altijd hetzelfde was voor het schrijven van stabiele unit-tests.

Als het toevallig is wat u probeert te bereiken, of een andere uitvoergerelateerde taak, hoeft u helemaal niets te sorteren, gebruik gewoon de pprint-module, naast andere functies zal het sorteer woordenboeken op sleutel.

>>> d = {'a':1, 'b':2, 'c':3}
>>> print d
{'a': 1, 'c': 3, 'b': 2}
>>> from pprint import pprint
>>> pprint(d)
{'a': 1, 'b': 2, 'c': 3}

Other episodes