2012-03-23 37 views
7

Estoy tratando de eliminar elementos de una lista anidada en Python. Tengo una lista anidada de la siguiente manera:Eliminar elementos de una lista anidada Python

families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]] 

Quiero eliminar las entradas de cada sublista que coorespond a la posición de indexado de la lista secundaria en la lista maestra. Entonces, por ejemplo, necesito eliminar 0 de la primera sublista, 1 de la segunda sublista, etc. Estoy tratando de usar una lista de aprehensión, haz esto. Esto es lo que he intentado:

familiesNew = [ [ families[i][j] for j in families[i] if i !=j ] for i in range(len(families)) ] 

Esto funciona para range(len(families)) hasta 3, sin embargo, más allá de eso me sale IndexError: list index out of range. No estoy seguro por qué. ¿Alguien puede darme una idea de cómo hacer esto? Preferiblemente un trazador de líneas (lista de comprensión).

Gracias.

Respuesta

9

Casi lo tienes bien. Basta con sustituir families[i][j] con j y funciona:

>>> [ [ j for j in families[i] if i !=j ] for i in range(len(families)) ] 
[[1, 2], [0, 2, 3], [0, 1, 3, 4], [1, 2, 4, 5], [2, 3, 5, 6]] 

Se puede escribir un poco más limpia usando la función enumerate:

>>> [[f for f in family if f != i] for i, family in enumerate(families)] 
[[1, 2], [0, 2, 3], [0, 1, 3, 4], [1, 2, 4, 5], [2, 3, 5, 6]] 

O incluso utilizando remove si no te importa el cambio de la lista original:

>>> for i, family in enumerate(families): family.remove(i) 
+0

Gracias, me decidí a ir con la última opción, ya que en realidad era bueno y deseable cambiar la lista en su lugar. – johntfoster

3

¿Hace esto que usted quiere?

familiesNew=[ filter(lambda x:x!=i,j) for i,j in enumerate(families) ] 

EDITAR

Tenga en cuenta también, la razón por la suya fallidos se debe a que en el tercer elemento de la lista externa ([1, 2, 3, 4, 5]) que está tratando de conseguir el quinto elemento en su bucle (= for j in families[i] = for j in [1,2,3,4,5]), pero las familias [i] tiene una longitud de 5, lo que significa que el índice es mayor 4. lo siento si esa explicación es un poco confuso ... tal vez el siguiente le ayudará a aclararlo un poco:

families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]] 

def f(i,j): 
    print i,j,families[i] 
    return families[i][j] 
#THIS DOES NOT WORK -- but it will tell you where it failed. 
familiesNew = [ [ f(i,j) for j in families[i] if i !=j ] for i in range(len(families)) ] 
5

Pregunta editada, eliminando la respuesta que estaba resolviendo el problema incorrecto. Además, añadió respuesta adicional por @Ashwini:

Para efectos de comparación:

root# python -m timeit 'families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]]' '[x.remove(ind) for ind,x in enumerate(families) ]' 
100000 loops, best of 3: 3.42 usec per loop  

root# python -m timeit -s 'families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]]' '[[f for f in family if f != i] for i, family in enumerate(families)]' 
100000 loops, best of 3: 4.87 usec per loop 

root# python -m timeit -s 'families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]]' '[ filter(lambda x:x!=i,j) for i,j in enumerate(families) ]' 
100000 loops, best of 3: 7.99 usec per loop 

Estos son micro-segundos, así que creo que lo que quiere hacer está bien a menos que usted va a estar haciendo esto un lote veces.

+0

Creo que la semántica de esto no es del todo correcta. No es que el elemento en el * index * 'i' deba eliminarse de cada sublista, sino el elemento' i' en sí mismo. –

+0

Este es un truco inteligente, pero creo que no acaba de hacer lo que está destinado a hacer. (Funcionaría si los últimos elementos de la lista externa fueran secuencias que comienzan en 0). +1 por tiempo aunque sin embargo. – mgilson

+0

Mi error por haber malinterpretado la intención de la pregunta (y luego por no verificar la salida para que coincida) – sberry

2

Si desea modificar la lista original, entonces intente esto:

>>>[x.remove(ind) for ind,x in enumerate(families) ] 
>>>families 
[[1, 2], [0, 2, 3], [0, 1, 3, 4], [1, 2, 4, 5], [2, 3, 5, 6]] 
+0

Esta respuesta es interesante porque hace el cálculo en su lugar. Presumiblemente devolvería una lista de Ninguno ... pero eso podría estar bien para algunas aplicaciones. – mgilson

+0

¡sí! esta lista de comprensión devolverá una lista de Ninguno de longitud == len (familias) y modificará la lista original. –

+0

buena solución, aunque generalmente se considera de mala educación utilizar una lista de comprensión de los efectos secundarios. –

Cuestiones relacionadas