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