В чем разница между добавлением и назначением значения в список?

1

Когда я использую цикл с одной строкой в Python, я получаю два разных значения в зависимости от выбранного мной процесса (Назначение и добавление процессов). Я хочу понять разницу и то, как они работают. В следующих двух примерах я пытаюсь написать программу, которая возвращает список, содержащий только те элементы, которые являются общими для списков (без дубликатов).

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

a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

def common_in_two_lists(list1, list2):
   re_list = []
   [re_list.append(val1) for val1 in list1 for val2 in list2 if val1==val2 and val1 not in re_list]
   return re_list

После вызова функции и списка выходных данных:

l = common_in_two_lists(a, b)
print(l)

и выход:

[1, 2, 3, 5, 8, 13]

Но когда я использую метод назначения как следующий, я получаю неправильный ответ:

def common_in_two_lists(list1, list2):
   re_list = []
   re_list = [val1 for val1 in list1 for val2 in list2 if val1==val2 and val1 not in re_list]
   return re_list

l = common_in_two_lists(a, b)
print(l)

и выход:

[1, 1, 2, 3, 5, 8, 13]

Любой может научить меня понимать, как это происходит по-разному?

  • 2
    Злоупотребление списочным пониманием для побочного эффекта является большим нет-нет ( stackoverflow.com/questions/5753597/… ). Кроме того, во втором примере re_list = [] не требуется, так как следующая строка создает новый список в любом случае. re_list = [val1 for val1 in list1 for val2 in list2 if val1 == val2] будет иметь точно такой же результат.
  • 0
    В первом случае вы изменяете список с каждым циклом. Когда вы дойдете до второй 1 уже есть 1 в re_list .
Показать ещё 5 комментариев
Теги:
python-3.x
for-loop

3 ответа

3
Лучший ответ

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

a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]


def common_in_two_lists1(list1, list2):
    re_list = []
    for val1 in list1:
        for val2 in list2:
            if val1 == val2 and val1 not in re_list:
                re_list.append(val1)
                print(re_list)
    return re_list


l = common_in_two_lists1(a, b)

ВЫХОД

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 5]
[1, 2, 3, 5, 8]
[1, 2, 3, 5, 8, 13]

Вы можете видеть, что re_list значение каждый раз. И [] вы положили для первого примера, бесполезны.

Перейдем к вашему второму примеру. Если вы проверите тип выражения, вы найдете его генератором.

re_list = print(type(val1 for val1 in list1 for val2 in list2 if val1 == val2 and val1 not in re_list))
<class 'generator'>

И выражение генератора оценивается только тогда, когда вы пытаетесь извлечь значение, что объясняет, почему вы получаете дубликат 1 в этом коде. Потому что в выражении re_list пуст при создании генератора.

Наконец, придя к вашему решению:

Я пытаюсь написать программу, которая возвращает список, содержащий только те элементы, которые являются общими для списков (без дубликатов).

Вы должны следовать рекомендациям Jon Clements и применять его с помощью набора

вы должны взглянуть на множества... например: list (set (a).intersection(b))

  • 0
    Но я все еще получаю NameError, если удалить бесполезный re_list = [] из моего первого примера. Почему?
  • 0
    @JosephSh re_list = [] не бесполезен, он очень необходим, поскольку требуется для объявления. Вы не можете добавить в список, пока не объявите его.
Показать ещё 1 комментарий
2

Во втором примере re_list пуст к моменту создания нового списка, поэтому val1 not in re_list всегда false. В первом вы создаете список того, что возвращается re_list.append() (None, как я помню) и назначить его в никуда, модифицируя re_list.

Кстати, почему бы вам не использовать set() для получения списка уникальных элементов?

  • 0
    Как мы можем использовать set() для получения списка уникальных элементов?
1
def common_in_two_lists(list1, list2):
   re_list = []
   [re_list.append(val1) for val1 in list1 for val2 in list2 if val1==val2 and val1 not in re_list]
   return re_list

эквивалентно:

def common_in_two_lists(list1, list2):
   re_list = []
   for val1 in list1:
       for val2 in list2:
          if val1==val2 and val1 not in re_list:
             re_list.append(val1)
   return re_list

тогда как второй метод:

def common_in_two_lists(list1, list2):
   re_list = []
   re_list = [val1 for val1 in list1 for val2 in list2 if val1==val2 and val1 not in re_list]
   return re_list

эквивалентно

def common_in_two_lists(list1, list2):
    re_list_old = []
    re_list = []
    for val1 in list1:
        for val2 in list2:
            if val1==val2 and val1 not in re_list_old: #note re_list_old here
                re_list.append(val1)
    return re_list

Стоит заметить, что со вторым методом вы не проверяете дубликаты в конечном списке, потому что каждый раз, когда вы проверяете пустой список при выполнении val1 not in re_list

Оба способа работают в O(n**2) сложности времени, используя наборы:

l = list(set(a) & set(b))

это более эффективно и проще, так как вы можете сделать это со средней временной сложностью O(min(len(a), len(b)) (худший случай - O(len(a)*len(b))).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню