我编写了一个基于迭代器的小程序来显示多列日历。
在该代码中,我使用master
按功能itertools.groupby
按月对日期进行分组。在那里,我将月份名称和分组日期作为每个月的列表。但是,当我让该函数直接将分组日期作为迭代器(而不是列表)返回时,程序会将除最后一列之外的所有日期留空。
我无法弄清楚为什么会这样。我使用groupby错了吗?任何人都可以帮我找到消耗迭代器的位置或忽略其输出吗?为什么特别是最后一栏“幸存”?
以下是代码:
group_by_months()
这是失败的输出:
import datetime
from itertools import zip_longest, groupby
def grouper(iterable, n, fillvalue=None):
"""\
copied from the docs:
https://docs.python.org/3.4/library/itertools.html#itertools-recipes
"""
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
def generate_dates(start_date, end_date, step=datetime.timedelta(days=1)):
while start_date < end_date:
yield start_date
start_date += step
def group_by_months(seq):
for k,v in groupby(seq, key=lambda x:x.strftime("%B")):
yield k, v # Why does it only work when list(v) is yielded here?
def group_by_weeks(seq):
yield from groupby(seq, key=lambda x:x.strftime("%2U"))
def format_month(month, dates_of_month):
def format_week(weeknum, dates_of_week):
def format_day(d):
return d.strftime("%3e")
weekdays = {d.weekday(): format_day(d) for d in dates_of_week}
return "{0} {7} {1} {2} {3} {4} {5} {6}".format(
weeknum, *[weekdays.get(i, " ") for i in range(7)])
yield "{:^30}".format(month)
weeks = group_by_weeks(dates_of_month)
yield from map(lambda x:format_week(*x), weeks)
start, end = datetime.date(2016,1,1), datetime.date(2017,1,1)
dates = generate_dates(start, end)
months = group_by_months(dates)
formatted_months = map(lambda x: (format_month(*x)), months)
ncolumns = 3
quarters = grouper(formatted_months, ncolumns)
interleaved = map(lambda x: zip_longest(*x, fillvalue=" "*30), quarters)
formatted = map(lambda x: "\n".join(map(" ".join, x)), interleaved)
list(map(print, formatted))
这是预期的输出:
January February March
09 1 2 3 4 5
10 6 7 8 9 10 11 12
11 13 14 15 16 17 18 19
12 20 21 22 23 24 25 26
13 27 28 29 30 31
April May June
22 1 2 3 4
23 5 6 7 8 9 10 11
24 12 13 14 15 16 17 18
25 19 20 21 22 23 24 25
26 26 27 28 29 30
July August September
35 1 2 3
36 4 5 6 7 8 9 10
37 11 12 13 14 15 16 17
38 18 19 20 21 22 23 24
39 25 26 27 28 29 30
October November December
48 1 2 3
49 4 5 6 7 8 9 10
50 11 12 13 14 15 16 17
51 18 19 20 21 22 23 24
52 25 26 27 28 29 30 31
答案 0 :(得分:3)
正如文档所述(c.f.):
当groupby()对象前进时,前一个组不再可见。因此,如果以后需要该数据,则应将其存储为列表
这意味着当代码稍后无序地访问返回的迭代器时,即当groupby实际被迭代时,消耗了迭代器。由于此处完成的分块和交错,迭代无序发生。
由于我们迭代的方式,我们观察到这种特定的模式(即,只有最后一列完全显示)。那就是:
打印第一行的月份名称。从而消耗了直到最后一列的月份的迭代器(并且丢弃了它们的内容)。 groupby()对象仅在第一列&#39;之后生成最后一列的月份名称。数据
我们打印第一周的行。因此,使用传递给zip_longest()
的默认值自动填充第一列已经耗尽的迭代器。只有最后一列仍然提供实际数据。
下一行的月份名称也是如此。