New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make itertools.islice supports negative values for start and stop arguments for sized iterable object #77221
Comments
d = OrderedDict()
for i in range(10): d[i] = i
dv = d.keys()
# dv is a KeysView which is a sized iterable
As it shows, I have to use For sized iterable objects, islice(dv, -1) For iterable objects which is not sized,
raises a ValueError as its original behavior. |
I do not think this is suitable for the itertools module. It is designed to work with iterators, i.e. with objects that support the iterator protocol. What if the iterable change the size during iteration? Should the islice iterator produce less or larger number of items than the initial estimation? Or detect this change and raise an error? Should it revive the iteration if new items were added after consuming the last item? These design questions should have thoughtful answers. And handling all corner cases will complicate the code. I afraid that after adding support of negative start and stop we will get a request for supporting negative step. It is possible to implement support of negative indices for arbitrary iterators using tee() or deque, but this will complicate the islice() code even more for a small niche case. This may be a use case for the new module that works specially with sequences. It will be added once we will have enough use cases. |
I concur with Serhiy. This doesn't make sense for itertools. Marking this as closed. Thank you for the suggestion. |
Now I have thought about it and realized that def drop_first(iterable, n=1):
for _ in range(n):
next(iterable)
for e in iterable:
yield e
def drop_last(iterable, n=1):
dq = deque()
for _ in range(n):
dq.append(next(iterable))
for e in iterable:
dq.append(e)
yield dq.popleft() |
I hope it's fine to add to closed topics here. I agree with the decision that islice should not handle a special case of sized containers vs iterables. However, I think that the support of negative indices in islice would be nice. A simple use case would be to get the last element of an iterable. I also agree that to support negative indices would require more work. Indeed, it seems that for each combination of positive/negative start/stop it required a new algorithm! I didn't implement negative steps. However, I think that because it's not easy to implement, it would be even better to include that in the standard library (because it would save other people from writing that). If we care about code reuse: I think that negative indices make the algorithm more useful, while non-trivial steps are redundant, because they can be implemented by a composition of a slice with step=1 with a simple slice with start, stop=None, None with step!=1. Negative slice fundamentally changes the algorithm: if one wants to have the flow inverted, fflow[0, None, -1], one would have to store it all in memory! Anyway it's easy to make this in a separate function. So I think it's more functional to implement negative indices and discard negative steps (or non-trivial steps at all). About drop_first, drop_last suggested above: I also think that they are redundant and would be better incorporated into islice. |
Sorry for a typo. The paragraph before the last should read Negative *step* fundamentally changes the algorithm:... flow[-1:None:-1]. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: