Tengo una lista anidada como esta que:

list = [[1,2,3], [2,5,7,6], [1,-1], [5,7], [6,3,7,4,3], [2, 5, 1, -5]]

Lo que intento hacer es eliminar listas anidadas, donde el valor dentro de estas listas es positivo y negativo. He intentado hacerlo por comprensión de la lista, pero no pude resolverlo.

def method(list):
    return [obj for obj in list if (x for x in obj if -x not in obj)]

Los resultados obtenidos deben ser como:

 list = [[1,2,3], [2,5,7,6], [5,7], [6,3,7,4,3]]
4
Robert Kodra 2 oct. 2019 a las 23:07

6 respuestas

La mejor respuesta

Suponiendo que desea listas donde los elementos son negativos o positivos, puede usar la función predefinida all para verificar ambas posibilidades

result = [L for L in x if all(y>0 for y in L) or all(y<0 for y in L)]

Editar:

En los comentarios aclaraste qué es una lista válida (por ejemplo, [-1, 2] es válida) ... con esta nueva formulación, la prueba debería ser

result = [L for L in x if all(-y not in L for y in L)]

Donde cada prueba es ahora sin embargo cuadrática en el tamaño de la lista. Usando set este problema puede eliminarse

result = [L for L in x if all(-y not in S for S in (set(L),) for y in L)]
5
6502 3 oct. 2019 a las 09:18

Su generador debe ceder si se aplica la condición para filtrar un objeto.
Luego alimenta el generador a un agregador para determinar si obj debe ser filtrado.
el agregador podría ser cualquiera o todos, o algo diferente.

# assuming obj should be filtered if both x and the inverse of x are in obj
def method_with_all(src):
    return [obj for obj in src if all(-x not in obj for x in obj)]

def method_with_any(src):
    return [obj for obj in src if any(-x in obj for x in obj)]

2
steviestickman 2 oct. 2019 a las 20:29

Puede filtrar las listas que tienen elementos negativos y positivos:

def keep_list(nested_list):

    is_first_positive = nested_list[0] > 0

    for element in nested_list[1:]:
        if (element > 0) != is_first_positive:
            return False

    return True


my_list = [[1,2,3], [2,5,7,6], [1,-1], [5,7], [6,3,7,4,3], [2, 5, 1, -5]]

print(list(filter(keep_list, my_list)))

Salida:

[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
0
kederrac 2 oct. 2019 a las 20:24

Numpy también se puede usar. Mi solución aquí es similar a la operación "todos" sugerida por otros pero codificada explícitamente y solo necesita una condición. Comprueba si el signo de todos los elementos es igual al signo del primer elemento (también podría ser cualquier otro).

from numpy import *    

def f(b): 
   return [a for a in b if sum(sign(array(a)) == sign(a[0])) == len(a)]

Para tu caso ...

data = [[1,2,3], [2,5,7,6], [1,-1], [5,7], [6,3,7,4,3], [2, 5, 1, -5]]
print(f(data))

... volverá:

[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
0
Jojo 2 oct. 2019 a las 22:21

Usando la comprensión de la lista puedes hacer algo como:

def method2(list):
    return [obj for obj in list if (all(n>0 for n in obj) or all(n<0 for n in obj))]

Que, con tu ejemplo, da como resultado:

[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
3
FabioL 2 oct. 2019 a las 20:24

En general es mejor dividir la tarea por pasos:

  1. La lista dada encuentra los aspectos positivos (función positives)
  2. En la lista dada, encuentre los negativos y multiplíquelos por -1 (función negatives)
  3. Si la intersección de los positivos y negativos no está vacía, elimine.

Entonces, podrías hacer:

def positives(ls):
    return set(l for l in ls if l > 0)


def negatives(ls):
    return set(-1*l for l in ls if l < 0)


list = [[1, 2, 3], [2, 5, 7, 6], [1, -1], [5, 7], [6, 3, 7, 4, 3], [2, 5, 1, -5]]
result = [l for l in list if not negatives(l) & positives(l)]

print(result)

Salida

[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]

Como nota al margen, no debe usar list como nombre de variable, ya que oculta la función de lista integrada.

2
Dani Mesejo 2 oct. 2019 a las 20:14
58208677