Si tengo una lista:

to_modify = [5,4,3,2,1,0]

Y luego declara otras dos listas:

indexes = [0,1,3,5]
replacements = [0,0,0,0]

¿Cómo puedo tomar los elementos de to_modify como índice a indexes, luego establecer los elementos correspondientes en to_modify a replacements, es decir, después de ejecutar, indexes debería ser { {X5}}.

Aparentemente, puedo hacer esto a través de un bucle for:

for ind in to_modify:
    indexes[to_modify[ind]] = replacements[ind]

¿Pero hay otra manera de hacer esto? ¿Puedo usar operator.itemgetter de alguna manera?

27
Alcott 29 ago. 2011 a las 18:04

7 respuestas

La mejor respuesta

El mayor problema con su código es que es ilegible. Regla número uno del código de Python, si no es legible, nadie lo verá lo suficiente como para obtener información útil. Siempre use nombres descriptivos de variables. Casi no captó el error en su código, veámoslo nuevamente con buenos nombres, estilo de reproducción en cámara lenta:

to_modify = [5,4,3,2,1,0]
indexes = [0,1,3,5]
replacements = [0,0,0,0]

for index in indexes:
    to_modify[indexes[index]] = replacements[index]
    # to_modify[indexes[index]]
    # indexes[index]
    # Yo dawg, I heard you liked indexes, so I put an index inside your indexes
    # so you can go out of bounds while you go out of bounds.

Como es obvio cuando usa nombres descriptivos de variables, está indexando la lista de índices con valores propios, lo que no tiene sentido en este caso.

Además, al iterar a través de 2 listas en paralelo, me gusta usar la función zip (o izip si le preocupa el consumo de memoria, pero no soy uno de esos puristas de iteración). Intenta esto en su lugar.

for (index, replacement) in zip(indexes, replacements):
    to_modify[index] = replacement

Si su problema solo es trabajar con listas de números, entonces diría que @steabert tiene la respuesta que estaba buscando con esas cosas molestas. Sin embargo, no puede utilizar secuencias u otros tipos de datos de tamaño variable como elementos de matrices numpy, por lo que si su variable to_modify tiene algo así, probablemente sea mejor hacerlo con un bucle for.

34
machine yearning 2 sep. 2011 a las 19:12

Puedes resolverlo usando el diccionario

to_modify = [5,4,3,2,1,0]
indexes = [0,1,3,5]
replacements = [0,0,0,0]

dic = {}
for i in range(len(indexes)):
    dic[indexes[i]]=replacements[i]
print(dic)

for index, item in enumerate(to_modify):
    for i in indexes:
        to_modify[i]=dic[i]
print(to_modify)

La salida será

{0: 0, 1: 0, 3: 0, 5: 0}
[0, 0, 3, 0, 1, 0]
0
Akram Samarikhalaj 12 may. 2019 a las 20:56

Puedes usar operator.setitem.

from operator import setitem
a = [5, 4, 3, 2, 1, 0]
ell = [0, 1, 3, 5]
m = [0, 0, 0, 0]
for b, c in zip(ell, m):
    setitem(a, b, c)
>>> a
[0, 0, 3, 0, 1, 0]

¿Es más legible o eficiente que su solución? ¡No estoy seguro!

0
Praveen Gollakota 29 ago. 2011 a las 14:31

¿Por qué no solo:

map(s.__setitem__, a, m)
8
eph 29 ago. 2011 a las 16:10

Numpy tiene matrices que le permiten usar otras listas / matrices como índices:

import numpy
S=numpy.array(s)
S[a]=m
20
steabert 29 ago. 2011 a las 14:22

Un poco más lenta, pero legible creo:

>>> s, l, m
([5, 4, 3, 2, 1, 0], [0, 1, 3, 5], [0, 0, 0, 0])
>>> d = dict(zip(l, m))
>>> d  #dict is better then using two list i think
{0: 0, 1: 0, 3: 0, 5: 0}
>>> [d.get(i, j) for i, j in enumerate(s)]
[0, 0, 3, 0, 1, 0]
2
utdemir 29 ago. 2011 a las 14:34

para índice en a:

Esto hará que index tome los valores de los elementos de a, por lo que usarlos como índices no es lo que desea. En Python, iteramos sobre un contenedor al iterar sobre él.

"Pero espera", dices, "Para cada uno de esos elementos de a, necesito trabajar con el elemento correspondiente de m. ¿Cómo se supone que debo hacer eso sin índices?"

Sencillo. Transformamos a y m en una lista de pares (elemento de a, elemento de m) e iteramos sobre los pares. Lo cual es fácil de hacer: simplemente use la función de biblioteca incorporada zip, de la siguiente manera:

for a_element, m_element in zip(a, m):
  s[a_element] = m_element

Para que funcione de la manera que intentaba hacerlo, tendría que obtener una lista de índices para repetir. Esto es factible: podemos usar range(len(a)) por ejemplo. ¡Pero no hagas eso! Así no es como hacemos las cosas en Python. En realidad, iterar directamente sobre lo que quieres repetir es una idea hermosa y liberadora de la mente.

¿Qué pasa con operator.itemgetter

No es realmente relevante aquí. El propósito de operator.itemgetter es convertir el acto de indexación en algo, en algo similar a una función (lo que llamamos "invocable"), para que pueda usarse como devolución de llamada (por ejemplo, una tecla ' 'para operaciones de clasificación o mín. / máx.). Si lo usáramos aquí, tendríamos que volver a llamarlo cada vez a través del bucle para crear un nuevo elemento, solo para poder usarlo inmediatamente una vez y tirarlo. En contexto, eso es solo trabajo ocupado.

1
Karl Knechtel 29 ago. 2011 a las 15:22