Создание списка из существующего списка, если в Python выполняется условие - PullRequest
0 голосов
/ 30 ноября 2011

Я пытаюсь удалить некоторые элементы из списка,

list1 = ["CCC-C", "CCC-P", "CCC-A-P", "CCC-A-H", "CCC-J", "CCC-S-X"]
new_list = [i for i in list1 if (len(i) == 5 or len(i) == 7 or i[6] != "H")]

Если какой-либо элемент в list1 не имеет длины 5 или 7 или его седьмой символ "H", он не долженнаходиться в new_list.

Но приведенный выше код включает в себя пункт "CCC-AH" в new_list.Кроме того, он не выдает ошибку «IndexError: строковый индекс вне диапазона» при проверке i [6] для элемента «CCC-C».Есть идеи?

С уважением,

Ответы [ 4 ]

2 голосов
/ 30 ноября 2011

Сделайте это:

new_list = [i for i in list1 if len(i)==5 or (len(i)==7 and i[6]!="H")]

Таким образом, вы получаете только предметы длиной 5 (условие len(i)==5) или предметы длиной 7, если только последний символ не является H (условие (len(i)==7 and i[6]!="H")).

Потенциально IndexError -прогнозное условие i[6]!="H" будет оцениваться только в том случае, если строка имеет длину 7, гарантируя, что вы не получите эту ошибку.

2 голосов
/ 30 ноября 2011

Логическое выражение в Python выполняется в следующем порядке:

>>> A() or B()

Если A () возвращает True, нет необходимости проверять B ()

>>> A() and B()

Если A () возвращает False, нет необходимости проверять B ()

Надеюсь, это даст вам некоторое представление.

0 голосов
/ 30 ноября 2011

Как уже отмечали другие, len("CCC-A-H") == 7 и python используют оценку короткого замыкания в логических операциях.Конечным результатом является то, что:

(len("CCC-A-H") == 5 or len("CCC-A-H") == 7 or "CCC-A-H"[6] != "H")

вернет true, поскольку len("CCC-A-H") == 7 оценивается как true до "CCC-A-H"[6] != "H".

Это может быть легче увидеть с помощью filter(...)функция вместо понимания списка:

list1 = ["CCC-C", "CCC-P", "CCC-A-P", "CCC-A-H", "CCC-J", "CCC-S-X"]
def len57notHWrong(item):
    return len(item) == 5 or len(item) == 7 or item[6] != "H"

print "Wrong           : ", filter(len57notHWrong, list1)

Это простой прямой перевод понимания списка, который вы использовали при использовании функции filter(...).

Если бы мы переписали это, используя if ... elif ... else конструкции, это будет выглядеть примерно так:

def len57notHWrongExpanded(item):
    if len(item) == 5:     # first check if length is 5
        return True
    elif len(item) == 7:   # now check if length is 7
        return True        # it's 7? Short-circuit, return True
    elif item[6] != "H": # This will never get seen (on this particular dataset)
        return True

    return False

print "Wrong (Expanded): ", filter(len57notHWrongExpanded, list1)

Правильное выражение будет выглядеть следующим образом:

def len57notH(item):
    return len(item) == 5 or (len(item) == 7 and item[6] != "H")

print "Correct         : ", filter(len57notH, list1)

Expanded:

def len57notHExpanded(item):
    if len(item) == 5:
        return True
    elif len(item) == 7:
        if item[6] != "H":
            return True
    return False

print "Correct (Expand): ", filter(len57notHExpanded, list1)

Это будет делатьпонимание списка выглядит так:

new_list = [i for i in list1 if (len(i) == 5 or (len(i) == 7 and i[6] != "H"))]

Причина, по которой ваш код не вызывает ошибку IndexError, заключается в том, что все ваши элементы данных имеют длину 5 или 7 элементов.Это приводит к короткому замыканию кода перед попаданием в выражение i[6] != "H".Если вы попробуете этот код в списке, который содержит элементы данных, которые не имеют длину 5 или 7 и длину менее 7 элементов, то возникает IndexError:

list2 = ["CCC-C", "CCC-P", "CCC", "CCC-A-P", "CCC-A-H", "CCC-J", "CCC-S-X"]
new_list = [i for i in list2 if (len(i) == 5 or len(i) == 7 or i[6] != "H")]

Traceback (most recent call last):
  File "C:/Users/xxxxxxxx/Desktop/t.py", line 44, in <module>
    new_list = [i for i in list2 if (len(i) == 5 or len(i) == 7 or i[6] != "H")]
IndexError: string index out of range

Извините, это немного длинный ответ...

0 голосов
/ 30 ноября 2011

Кроме того, он не выдает ошибку «IndexError: строковый индекс вне диапазона» при проверке i [6] для элемента «CCC-C».

or короткое замыкание. Если первое условие, заданное для условия или, является True, то оно не вычисляет второе, так как независимо от значения истинности второго аргумента общее оценочное значение остается True.

Кроме того, "CCC-A-H" соответствует, потому что его длина равна 7. Если вы не хотите, чтобы строки, заканчивающиеся на H в седьмой позиции, независимо от их длины, вам следует переделать логическое выражение:

new_list = [i for i in list1 if (len(i) == 5 or len(i) == 7) and (i[6] != "H")]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...