ordereddict dict python python-3.x dictionary python-2.x ordereddictionary

python - ordereddict to json



¿Cómo puedo agregar un elemento en la parte superior de un OrderedDict en Python? (9)

tengo esto

d1 = OrderedDict([(''a'', ''1''), (''b'', ''2'')])

Si hago esto

d1.update({''c'':''3''})

Entonces entiendo esto

OrderedDict([(''a'', ''1''), (''b'', ''2''), (''c'', ''3'')])

pero quiero esto

[(''c'', ''3''), (''a'', ''1''), (''b'', ''2'')]

sin crear un nuevo diccionario


Acabo de escribir una subclase de OrderedDict en un proyecto mío para un propósito similar. Aquí está la esencia .

Las operaciones de inserción también son tiempo constante O(1) (no requieren que reconstruya la estructura de datos), a diferencia de la mayoría de estas soluciones.

>>> d1 = ListDict([(''a'', ''1''), (''b'', ''2'')]) >>> d1.insert_before(''a'', (''c'', 3)) >>> d1 ListDict([(''c'', 3), (''a'', ''1''), (''b'', ''2'')])


Es posible que desee utilizar una estructura diferente por completo, pero hay formas de hacerlo en Python 2.7 .

d1 = OrderedDict([(''a'', ''1''), (''b'', ''2'')]) d2 = OrderedDict(c=''3'') d2.update(d1)

d2 contendrá entonces

>>> d2 OrderedDict([(''c'', ''3''), (''a'', ''1''), (''b'', ''2'')])

Como lo mencionaron otros, en Python 3.2 puede usar move_to_end para mover una tecla determinada después de la inserción.

Nota: Tenga en cuenta que la primera opción es más lenta para grandes conjuntos de datos debido a la creación de un nuevo OrderedDict y la copia de valores antiguos.


Esto ahora es posible con move_to_end (key, last = True)

>>> d = OrderedDict.fromkeys(''abcde'') >>> d.move_to_end(''b'') >>> ''''.join(d.keys()) ''acdeb'' >>> d.move_to_end(''b'', last=False) >>> ''''.join(d.keys()) ''bacde''

move_to_end


FWIW Aquí hay un código rápido y sucio que escribí para insertar en una posición de índice arbitraria. No necesariamente eficiente, pero funciona en el lugar.

class OrderedDictInsert(OrderedDict): def insert(self, index, key, value): self[key] = value for ii, k in enumerate(list(self.keys())): if ii >= index and k != key: self.move_to_end(k)


No hay un método incorporado para hacerlo en Python 2. Si necesita esto, necesita escribir un método / función OrderedDict prepend() que opere en las OrderedDict internas de OrderedDict con complejidad O (1).

Para Python 3.2 y posterior, puede usar el método move_to_end 1 . El método acepta un last argumento que indica si el elemento se moverá a la parte inferior ( last=True ) o la parte superior ( last=False ) del OrderedDict .

Finalmente, si quieres una solución rápida, sucia y lenta , puedes crear un nuevo OrderedDict desde cero.

Detalles para las cuatro soluciones diferentes:

Extienda OrderedDict y agregue un nuevo método de instancia

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)

Manifestación:

>>> 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'')])

Función OrderedDict que manipula objetos OrderedDict

Esta función hace lo mismo al aceptar el objeto dict, clave y valor. Yo personalmente prefiero la clase:

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)

Manifestación:

>>> 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'')])

Utilice OrderedDict.move_to_end() (Python> = 3.2)

1 Python 3.2 introdujo el método move_to_end . Utilizándolo, podemos mover una clave existente a cualquiera de los extremos del diccionario en O (1) vez.

>>> 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 necesitamos insertar un elemento y moverlo a la parte superior, todo en un solo paso, podemos usarlo directamente para crear un contenedor prepend() (no presentado aquí).

Crea un nuevo OrderedDict - ¡lento!

Si no quiere hacer eso y el rendimiento no es un problema, entonces la manera más fácil es crear un nuevo 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

salida:

OrderedDict([(''c'', 3), (''e'', 5), (''a'', ''1''), (''b'', ''2'')])


Si necesita una funcionalidad que no está allí, simplemente amplíe la clase con lo que desee:

from collections import OrderedDict class OrderedDictWithPrepend(OrderedDict): def prepend(self, other): ins = [] if hasattr(other, ''viewitems''): other = other.viewitems() for key, val in other: if key in self: self[key] = val else: ins.append((key, val)) if ins: items = self.items() self.clear() self.update(ins) self.update(items)

No es terriblemente eficiente, pero funciona:

o = OrderedDictWithPrepend() o[''a''] = 1 o[''b''] = 2 print o # OrderedDictWithPrepend([(''a'', 1), (''b'', 2)]) o.prepend({''c'': 3}) print o # OrderedDictWithPrepend([(''c'', 3), (''a'', 1), (''b'', 2)]) o.prepend([(''a'',11),(''d'',55),(''e'',66)]) print o # OrderedDictWithPrepend([(''d'', 55), (''e'', 66), (''c'', 3), (''a'', 11), (''b'', 2)])


Si sabe que querrá una tecla ''c'', pero no conoce el valor, inserte ''c'' con un valor ficticio cuando cree el dict.

d1 = OrderedDict([(''c'', None), (''a'', ''1''), (''b'', ''2'')])

y cambia el valor más tarde.

d1[''c''] = 3


Sugiero agregar un método prepend() a esta recipe pura de Python o derivar una subclase de ella. El código para hacerlo podría ser bastante eficiente dado que la estructura de datos subyacente para ordenar es una lista enlazada.


Tienes que hacer una nueva instancia de OrderedDict . Si tus llaves son únicas:

d1=OrderedDict([("a",1),("b",2)]) d2=OrderedDict([("c",3),("d",99)]) both=OrderedDict(list(d2.items()) + list(d1.items())) print(both) #OrderedDict([(''c'', 3), (''d'', 99), (''a'', 1), (''b'', 2)])

Pero si no, tenga cuidado ya que este comportamiento puede o no ser deseado para usted:

d1=OrderedDict([("a",1),("b",2)]) d2=OrderedDict([("c",3),("b",99)]) both=OrderedDict(list(d2.items()) + list(d1.items())) print(both) #OrderedDict([(''c'', 3), (''b'', 2), (''a'', 1)])