Что такое интуиция за кодом ниже python, который использует itertools.chain и collection.Counter - PullRequest
0 голосов
/ 08 марта 2020

Что такое интуиция за кодом ниже python, где идентичный код дает два разных выхода?

import itertools as it
import collections

# Chained list not getting printed
l1 = [x for x in range(10)]
l2 = [y*2 for y in range(10)]

l3 = it.chain(l1,l2)
l4 = collections.Counter(l3)
print(list(l3))
print(l4)

# Counter dict not getting printed
l1 = [x for x in range(10)]
l2 = [y*2 for y in range(10)]

l3 = it.chain(l1,l2)
print(list(l3))
l4 = collections.Counter(l3)
print(l4)

Выход

[]
Counter({0: 2, 2: 2, 4: 2, 6: 2, 8: 2, 1: 1, 3: 1, 5: 1, 7: 1, 9: 1, 10: 1, 12: 1, 14: 1, 16: 1, 18: 1})

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Counter()

Обновление

Путем явного преобразования объекта itertools.chain в list выходы одинаковые.

import itertools as it
import collections

l1 = [x for x in range(10)]
l2 = [y*2 for y in range(10)]


l3 = it.chain(l1,l2)

print(type(l3))
l5 = list(l3)
l4 = collections.Counter(l5)
print(l5)
print(l4)

l1 = [x for x in range(10)]
l2 = [y*2 for y in range(10)]

l3 = it.chain(l1,l2)
l5 = list(l3)
print(l5)
l4 = collections.Counter(l5)
print(l4)

Выход

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Counter({0: 2, 2: 2, 4: 2, 6: 2, 8: 2, 1: 1, 3: 1, 5: 1, 7: 1, 9: 1, 10: 1, 12: 1, 14: 1, 16: 1, 18: 1})
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Counter({0: 2, 2: 2, 4: 2, 6: 2, 8: 2, 1: 1, 3: 1, 5: 1, 7: 1, 9: 1, 10: 1, 12: 1, 14: 1, 16: 1, 18: 1})

1 Ответ

0 голосов
/ 08 марта 2020

Во-первых, код не идентичен. В первом примере вы передаете l3 счетчику, прежде чем распечатать l3. Во втором примере вы печатаете l3, прежде чем передать его Counter. Таким образом, они не идентичны, поэтому не следует предполагать, что они имеют одинаковое поведение.

Далее вам нужно понять, что l3 является итератором. Это означает, что он разрешит итерацию по своим значениям, но только один раз. То есть, как только вы go пройдете все значения в l3, l3 будет пустым.

Итак, в вашем первом примере кода. Вы даете l3 счетчику, он проходит через все значения в нем, оставляя l3 пустым. поэтому, когда вы печатаете l3, вы действительно получаете пустой список. Потому что счетчик съел все значения из l3.

Во втором примере вы даете l3 для печати. Таким образом, print съедает все значения в l3, оставляя его пустым. Затем вы передаете пустой l3 в Counter, который правильно ничего не считает, так как вы дали ему l3, который является пустым.

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

Вы можете увидеть это поведение в простой форме, сделав итератор из вашего списка и просто вызвав print дважды. вы увидите, что первый отпечаток съедает все значения в итераторе, поэтому второй отпечаток печатает пустой итератор.

my_list = [1,2,3,4,5]
l3 = iter(my_list)
print(list(l3))
print(list(l3))

Вывод

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