# [Python-ideas] Set starting point for itertools.product()

Steven D'Aprano steve at pearwood.info
Thu Oct 25 07:31:00 EDT 2018

On Thu, Oct 25, 2018 at 02:31:05PM +0800, Ronie Martinez wrote:

> def main():
>     datetime_odometer = itertools.product(
>         range(2018, 10_000),  # year
>         range(1, 13),  # month
>         range(1, 31),  # days
>         range(0, 24),  # hours
>         range(0, 60),  # minutes
>         range(0, 60)  # seconds
>     )

When you talked about datetime, I thought you meant actual datetime
objects. The above is buggy: it ignores the 31st day of January, etc,
but includes February 29 and 30 every year.

>     datetime_of_interest = (2050, 6, 15, 10, 5, 0)
>
>     for i in datetime_odometer:
>         if i == datetime_of_interest: # target start time
>             break

In the most general case, there is no way to jump into the middle of an
arbitrary iterator, except to start at the beginning and compute the
values until you see the one that you want. Arbitrary iterators compute
their values on request, and there is no way to jump ahead except by
inspecting each value in turn, skipping the ones you don't want.

So unless I have missed something, I think what you are asking for is
impossible except for special cases like lists.

But in *this* case, modelling an odometer, that special case works:

def rotate(iterable, position):
L = list(iterable)
return L[position:] + L[:position]

Which gives us this:

py> months = rotate(range(1, 13), 5)
py> months
[6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5]

Now pass that to itertools.product.

In other words, I think that the right solution here is to construct
your iterables to start at the position you want, rather than expect
product() to jump into the middle of the sequence. (Which may not be
possible.)

--
Steve