T. Stone
T. Stone

Reputation: 19495

Getting the first and last item in a python for loop

Is there an elegant and pythonic way to trap the first and last item in a for loop which is iterating over a generator?

from calendar import Calendar

cal = Calendar(6)
month_dates = cal.itermonthdates(year, month)
for date in month_dates:
    if (is first item):     # this is fake
        month_start = date
    if (is last item):      # so is this
        month_end = date

This code is attempting to get the first day of the week the month ends on, and the last day of the week the month ends on. Example: for June, month-start should evaluate to 5/31/09. Even though it's technically a day in May, it's the first day of the week that June begins on.

Month-dates is a generator so i can't do the [:-1] thing. What's a better way to handle this?

Upvotes: 8

Views: 15365

Answers (4)

Tom Anderson
Tom Anderson

Reputation: 47183

Richie's got the right idea. Simpler:

month_dates = cal.itermonthdates(year, month)
month_start = month_dates.next()
for month_end in month_dates: pass # bletcherous

Upvotes: 11

Matthew Flaschen
Matthew Flaschen

Reputation: 284836

I would just force it into a list at the beginning:

from calendar import Calendar, SUNDAY

cal = Calendar(SUNDAY)
month_dates = list(cal.itermonthdates(year, month))

month_start = month_dates[0]
month_end = month_dates[-1]

Since there can only be 42 days (counting leading and tailing context), this has negligible performance impact.

Also, using SUNDAY is better than a magic number.

Upvotes: 11

John Y
John Y

Reputation: 14529

For this specific problem, I think I would go with Matthew Flaschen's solution. It seems the most straightforward to me.

If your question is meant to be taken more generally, though, for any generator (with an unknown and possibly large number of elements), then something more like RichieHindle's approach may be better. My slight modification on his solution is not to enumerate and test for element 0, but rather just grab the first element explicitly:

month_dates = cal.itermonthdates(year, month)
month_start = month_dates.next()
for date in month_dates:
    pass
month_end = date

Upvotes: 2

RichieHindle
RichieHindle

Reputation: 281495

How about this?

for i, date in enumerate(month_dates):
    if i == 0:
        month_start = date

month_end = date

enumerate() lets you find the first one, and the date variable falls out of the loop to give you the last one.

Upvotes: 10

Related Questions