2011-12-19 20 views
7

¿Cuál es la mejor manera de actualizar un valor en una lista de tuplas?Python: actualice un valor en una lista de tuplas

Actualmente lo hago como en el siguiente código, pero supongo que hay una manera más clara y concisa.

>>> foo = [('a', 'hello'), ('b', 'world')] 
>>> bar = dict(foo) 
>>> bar['b'] = 'friend' 
>>> foo = bar.items() 
>>> foo 
[('a', 'hello'), ('b', 'friend')] 

Editar: El motivo para utilizar una lista de tuplas no estaba claro en mi publicación original. El objetivo es actualizar algunos valores de encabezados de una aplicación wsgi durante el manejo de errores, que son una lista de tuplas.

Gracias de antemano.

+4

¿Por qué lista de tuplas necesita, no dict? Si el orden es importante, hay un [OrderedDict] (http://docs.python.org/library/collections.html#collections.OrderedDict) para usted. – DrTyrsa

+0

@DrTyrsa Esto es para actualizar los encabezados de una aplicación wsgi durante el manejo de errores, que son una lista de tuplas – Eric

Respuesta

6

Su estructura de datos (una lista de tuplas) es mejor referirse como una lista asociativa. Como otros señalaron, probablemente sea mejor usar un diccionario ya que obtendrás un mejor costo amortizado en la operación (inserción, eliminación y búsqueda son O (1) para un diccionario, pero la eliminación y la búsqueda son O (n) para asociativo lista).

En cuanto a la actualización de su lista asociativa convirtiéndola en un diccionario, y luego de vuelta a una lista asociativa, este método tiene tres inconvenientes. Es bastante caro, puede cambiar el orden de los artículos y eliminará los duplicados.

Si desea seguir usando listas asociativas, probablemente sea mejor utilizar una lista de comprensión para actualizar la estructura de datos.El costo será O (n) en tiempo y memoria, pero eso ya es lo que tiene cuando usa un diccionario intermedio.

He aquí una forma sencilla de hacerlo (requiere Python 2.5 a que utiliza el operador ternario):

def update_in_alist(alist, key, value): 
    return [(k,v) if (k != key) else (key, value) for (k, v) in alist] 

def update_in_alist_inplace(alist, key, value): 
    alist[:] = update_in_alist(alist, key, value) 

>>> update_in_alist([('a', 'hello'), ('b', 'world')], 'b', 'friend') 
[('a', 'hello'), ('b', 'friend')] 
+0

Código limpio y eficiente, ¡Gracias! – Eric

6

Dado que las tuplas son inmutables, deberá reemplazar la tupla por una nueva.

>>> foo[1] = (foo[1][0], "friend") 
>>> foo 
[('a', 'hello'), ('b', 'friend')] 

Por supuesto, esto solo funciona si conoce el índice del artículo que desea reemplazar. Si todo lo que tiene es el valor del primer elemento, entonces buscar en la lista para ese índice no es eficiente, especialmente para listas más grandes. Lo mismo aplica para su ejemplo anterior: convertir una lista en un dict y volver solo para cambiar algunas entradas no es una solución escalable.

Como mencionó eumiro y DrTysra en los comentarios, si su estructura de datos lo permite, es mejor que simplemente use un dict (o OrderedDict si el orden es importante).

+0

No creo que se conozca el índice, solo el primer elemento en tupla. – DrTyrsa

+0

@DrTyrsa buen punto. –

2

No tengo muy claro qué es lo que quiere lograr. Tuplas no se puede modificar, por lo que no puede cambiar ('b', 'world') a otra cosa. Pero puede modificar la lista, por supuesto:

foo[1] = ('b','friend') 

Si eso tiene sentido o no depende de su caso de uso. Si nos proporciona más detalles sobre el propósito real del código, podríamos proponer mejores soluciones.

+0

Gracias por su respuesta, actualicé la pregunta. Quiero actualizar algunos encabezados de una aplicación wsgi durante el manejo de errores. – Eric

3

Desde su uso, parece que realmente desea utilizar un diccionario para empezar, no una lista de tuplas. Si está tratando el primer campo de cada tupla como una clave única, conviértalo en un diccionario para que obtenga O (1) acceso y validación de que las claves son realmente únicas.

De lo contrario, debe buscar para encontrar el índice de la tupla que va a modificar, y luego sobrescribir esa ranura en la matriz con una nueva tupla, ya que las propias tuplas no se pueden modificar.

index = -1 
target = "b" 
new_value = "friend" 
for i, v in enumerate(foo): 
    if v[0] == target: 
    index = i 
    break 
if index >= 0: 
    foo[index] = (foo[index][0], new_value) 

Esto es, ciertamente, un poco torpe, pero de otro modo sencillo y al menos debería ser un poco más rápido (y menos memoria-hambrientos) que la solución actual. Se puede envolver trivialmente en una función para encapsularlo, por supuesto.

Cuestiones relacionadas