Il n'y a pas de méthode intégrée pour faire cela dans Python 2. Si vous en avez besoin, vous devez écrire un fichier prepend()
méthode/fonction qui opère sur le OrderedDict
internes avec une complexité O(1).
Pour Python 3.2 et les versions ultérieures, il faut devrait utiliser le move_to_end
méthode. La méthode accepte un last
qui indique si l'élément sera déplacé vers le bas ( last=True
) ou le haut ( last=False
) de la OrderedDict
.
Enfin, si vous voulez un rapide, sale et lent vous pouvez simplement créer une nouvelle OrderedDict
à partir de rien.
Détails pour les quatre solutions différentes :
Étendre le site OrderedDict
et ajouter une nouvelle méthode d'instance
from collections import OrderedDict
class MyOrderedDict(OrderedDict):
def prepend(self, key, value, dict_setitem=dict.__setitem__):
root = self._OrderedDict__root
first = root[1]
if key in self:
link = self._OrderedDict__map[key]
link_prev, link_next, _ = link
link_prev[1] = link_next
link_next[0] = link_prev
link[0] = root
link[1] = first
root[1] = first[0] = link
else:
root[1] = first[0] = self._OrderedDict__map[key] = [root, first, key]
dict_setitem(self, key, value)
Démonstration :
>>> d = MyOrderedDict([('a', '1'), ('b', '2')])
>>> d
MyOrderedDict([('a', '1'), ('b', '2')])
>>> d.prepend('c', 100)
>>> d
MyOrderedDict([('c', 100), ('a', '1'), ('b', '2')])
>>> d.prepend('a', d['a'])
>>> d
MyOrderedDict([('a', '1'), ('c', 100), ('b', '2')])
>>> d.prepend('d', 200)
>>> d
MyOrderedDict([('d', 200), ('a', '1'), ('c', 100), ('b', '2')])
Fonction autonome qui manipule OrderedDict
objets
Cette fonction fait la même chose en acceptant l'objet dict, key et value. Personnellement, je préfère la classe :
from collections import OrderedDict
def ordered_dict_prepend(dct, key, value, dict_setitem=dict.__setitem__):
root = dct._OrderedDict__root
first = root[1]
if key in dct:
link = dct._OrderedDict__map[key]
link_prev, link_next, _ = link
link_prev[1] = link_next
link_next[0] = link_prev
link[0] = root
link[1] = first
root[1] = first[0] = link
else:
root[1] = first[0] = dct._OrderedDict__map[key] = [root, first, key]
dict_setitem(dct, key, value)
Démonstration :
>>> d = OrderedDict([('a', '1'), ('b', '2')])
>>> ordered_dict_prepend(d, 'c', 100)
>>> d
OrderedDict([('c', 100), ('a', '1'), ('b', '2')])
>>> ordered_dict_prepend(d, 'a', d['a'])
>>> d
OrderedDict([('a', '1'), ('c', 100), ('b', '2')])
>>> ordered_dict_prepend(d, 'd', 500)
>>> d
OrderedDict([('d', 500), ('a', '1'), ('c', 100), ('b', '2')])
Utilisez OrderedDict.move_to_end()
(Python >= 3.2)
Introduction de Python 3.2 le site OrderedDict.move_to_end()
méthode. En l'utilisant, nous pouvons déplacer une clé existante vers l'une ou l'autre extrémité du dictionnaire en O(1) temps.
>>> d1 = OrderedDict([('a', '1'), ('b', '2')])
>>> d1.update({'c':'3'})
>>> d1.move_to_end('c', last=False)
>>> d1
OrderedDict([('c', '3'), ('a', '1'), ('b', '2')])
Si nous avons besoin d'insérer un élément et de le déplacer vers le haut, tout cela en une seule étape, nous pouvons l'utiliser directement pour créer un élément de type prepend()
(non présenté ici).
Créer un nouveau OrderedDict
- lent ! !!
Si vous ne voulez pas faire ça et la performance n'est pas un problème Le moyen le plus simple est de créer un nouveau dict :
from itertools import chain, ifilterfalse
from collections import OrderedDict
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
d1 = OrderedDict([('a', '1'), ('b', '2'),('c', 4)])
d2 = OrderedDict([('c', 3), ('e', 5)]) #dict containing items to be added at the front
new_dic = OrderedDict((k, d2.get(k, d1.get(k))) for k in \
unique_everseen(chain(d2, d1)))
print new_dic
sortie :
OrderedDict([('c', 3), ('e', 5), ('a', '1'), ('b', '2')])