[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


More information about the Python-ideas mailing list