Как создать генератор потока для данного итерируемого объекта
Напишите функцию, которая создаёт генератор потока для итерируемого объекта (list, generator и т.д.), чьи элементы содержат позицию и значение, и отсортированны по возрастанию позиции. Генератор потока должен быть равен исходному потоку (без учёта позиции), но с интервалами заполненными нулями. Например:
gen = gen_stream(9, [(4,111), (7,12)])
list(gen)
### Результат:
[0, 0, 0, 0, 111, 0, 0, 12, 0]
Индексация начинается с 0, следовательно позиция 111 в генераторе потока = 5 (индекс 4), позиция 12 = 8 (индекс 7). Таким образом индексы 4 и 7 заполнены двумя элементами из итерируемого объекта, остальные индексы нулями. Для упрощения задачи элементы исходного потока отсортированны - элемент с меньшей позицией предшествует элементу с большей позицией.
Первый параметр может быть None, в этом случае поток должен быть бесконечным, например бесконечный поток нулей:
gen_stream(None, [])
Следующий поток начинается с 0, 0, 0, 0, 111, 0, 0, 12, ... затем бесконечно генерируются нули:
gen_stream(None, [(4,111),(7,12)])
Функция также должна поддерживать кастомный экстрактор, который будет извлекать позицию и значение из более сложных объектов, например:
def day_extractor(x):
months = [31,28,31,30,31,31,30,31,30,31,30,31]
acc = sum(months[:x[1]-1]) + x[0] - 1
return (acc, x[2])
precipitation_days = [(3,1,4),(5,2,6)]
# 59 - ограничение потока суммой количества дней
# в январе и феврале: 31 + 28 = 59
list(gen_stream(59, precipitation_days, day_extractor))
# Результат:
[0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
precipitation_days имеет следующий формат: (d,m,mm), где d - номер дня в месяце, m - номер месяца, mm - осадки в миллиметрах.
Пример:
(3,1,4)- 3 января, осадки 4 mm(5,2,6)- 5 февраля, осадки 6 mm
Экстрактор передаётся как опциональный третий параметр со значением по умолчанию - лямбда функция, которая обрабатывает (position, value) пары, как в первом примере.
Вот что я сделал:
import sys
a=[(4,111),(7,12)]
n = 9
def gen_stream(n1, a1):
if n1==None:
b = [0 for i in range(sys.maxsize)]
else:
b = [0 for i in range(n1)]
for i in range(len(a1)):
b[a[i][0]]=a[i][1]
for i in range(len(b)):
yield b[i]
for i in gen_stream(None, a):
print(i)
Пока что дошёл до потока с бесконечными нулями, но функция не выполняется почему-то... И как сделать дальше с месяцами? У меня вылетает ошибка памяти, и прога жрёт много оперативы((( помогите пожалуйста
Ответы (2 шт):
Извините, решил за Вас. Задачка показалась интересной.
from itertools import count
def gen_stream(n, seq, extractor=lambda x: x):
seq = dict(map(extractor, seq))
iterable = count() if n is None else range(n)
for i in iterable:
yield seq.get(i, 0)
Вариант №1
def gen_stream(size, elements, extractor=lambda x: x):
def gen_zero():
while True:
yield 0
def gen_values_with_gaps(zeros_gen):
nonlocal cnt
# Вынимаем очередной элемент
for pos, val in map(extractor, elements):
# и пишем в поток нули до тех пор, пока
# счётчик не будет равен позиции
# на которую надо поставить элемент
for _ in range(pos - cnt):
yield next(zeros_gen)
# Когда счётчик поровнялся с нужной позицией
# пишем в поток значение элемента
yield val
# После того как элементы закончились, продолжаем
# писать в поток нули
yield from zeros_gen
cnt = 0
zeros_gen = gen_zero()
for val in gen_values_with_gaps(zeros_gen):
if size != None and cnt >= size:
break
yield val
cnt += 1
Вариант №2
def gen_stream(size, elements, extractor=lambda x: x):
elem_iter = iter(map(extractor, elements))
pos, val = next(elem_iter, (None, None))
cnt = 0
while size == None or cnt < size:
if cnt == pos:
yield val
pos, val = next(elem_iter, (None, None))
else:
yield 0
cnt += 1
Тестирование
test_gens = [
gen_stream(9,[(4,111),(7,12)]),
gen_stream(None,[(4,111),(7,12)]),
gen_stream(None, []),
gen_stream(9, [])
]
for gen in test_gens:
for cnt, v in enumerate(gen):
print(v, end=' ')
if cnt > 30:
break
print()
Output
0 0 0 0 111 0 0 12 0
0 0 0 0 111 0 0 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0