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 une prepend()
méthode / fonction qui opère sur les OrderedDict
internes avec une complexité O (1).
Python 3.2 et versions ultérieures, vous devez utiliser la move_to_end
méthode. La méthode accepte un last
argument qui indique si l'élément sera déplacé vers le bas ( last=True
) ou vers le haut ( last=False
) du OrderedDict
.
Enfin, si vous voulez une solution rapide, sale et lente , vous pouvez simplement en créer une nouvelle à OrderedDict
partir de zéro.
Détails des quatre solutions différentes:
Étendre 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émo:
>>> 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 les OrderedDict
objets
Cette fonction fait la même chose en acceptant l'objet, la clé et la valeur dict. 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émo:
>>> 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')])
Utiliser OrderedDict.move_to_end()
(Python> = 3.2)
Python 3.2 a introduit la OrderedDict.move_to_end()
méthode. En l'utilisant, nous pouvons déplacer une clé existante à l'une ou l'autre extrémité du dictionnaire en temps O (1).
>>> 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, le tout en une seule étape, nous pouvons directement l'utiliser pour créer un prepend()
wrapper (non présenté ici).
Créez un nouveau OrderedDict
- lent !!!
Si vous ne voulez pas faire cela et que les performances ne sont 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
production:
OrderedDict([('c', 3), ('e', 5), ('a', '1'), ('b', '2')])