Список головных болей понимания - PullRequest
4 голосов
/ 02 октября 2019

У меня есть такой вложенный список, который:

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

Я пытаюсь удалить вложенные списки, где значения в этих списках являются как положительными, так и отрицательными. Я пытался сделать это путем понимания списка, но я не мог понять это.

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

Полученные результаты должны быть такими:

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

Ответы [ 6 ]

5 голосов
/ 02 октября 2019

Предполагая, что вам нужны списки, в которых все элементы либо отрицательны, либо положительны, вы можете использовать предопределенную функцию all для проверки обеих возможностей

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

РЕДАКТИРОВАТЬ:

В комментариях выпояснил, что является действительным списком (например, [-1, 2] является действительным) ... с этой новой формулировкой тест должен быть

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

, где каждый отдельный тест теперь является квадратичным по размеру списка. Используя set эту проблему можно устранить

result = [L for L in x if all(-y not in S for S in (set(L),) for y in L)]
3 голосов
/ 02 октября 2019

Используя понимание списка, вы можете сделать что-то вроде:

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

, которое, на вашем примере, даст в качестве вывода:

[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
2 голосов
/ 02 октября 2019

Ваш генератор должен указывать, применимо ли условие фильтрации объекта.
Затем вы передаете генератор агрегатору, чтобы определить, нужно ли фильтровать obj.
Агрегатор может быть любым или всем, или чем-то другим.

# 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 голосов
/ 02 октября 2019

В общем случае лучше разбить задачу по шагам:

  1. По заданному списку найти положительные (positives функция)
  2. По заданному списку найти отрицательные и умножить их на -1 (negatives функция)
  3. Если пересечение как положительных, так и отрицательных не пусто, удалите.

Итак, вы можете сделать:

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)

Вывод

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

В качестве примечания не следует использовать список в качестве имени переменной, поскольку он скрывает встроенную функцию списка.

0 голосов
/ 03 октября 2019

Numpy также может быть использован. Мое решение здесь аналогично операции «все», предложенной другими, но закодировано явно и требует только одного условия. Он проверяет, равен ли знак всех элементов знаку первого элемента (может быть и любым другим).

from numpy import *    

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

Для вашего случая ...

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

... вернется:

[[1, 2, 3], [2, 5, 7, 6], [5, 7], [6, 3, 7, 4, 3]]
0 голосов
/ 02 октября 2019

Вы можете отфильтровать списки, которые имеют как отрицательные, так и положительные элементы:

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

output:

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