-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Iterators.reverse gives unexpected results when zipping iterators of different lengths #25583
Comments
cc @stevengj |
This is related to #20499. My sense is that if the (If they don't have lengths, |
Note that a similar issue arises for |
OK, added #20499 for triage. |
Triage decided not to throw an error when |
|
You mean, start with the element corresponding to the end of the shortest iterator? Makes sense. |
@mschauer, that cannot be done efficiently in general. It might be extremely inefficient if one iterator is much longer than the other. (Not to mention the case of infinite iterators etc.) |
One way to approach this is reversefrom(r::UnitRange, n::Integer) = reverse(first(r):min(last(r),first(r)+n-1))
reversefrom(it, n) = reverse(take(it, n))
reversefrom(z::Zip1, n) = Zip1(reversefrom(z.a, n))
reversefrom(z::Zip2, n) = Zip2(reversefrom(z.a, n), reversefrom(z.b, n))
reversefrom(z::Zip, n) = Zip(reversefrom(z.a, n), reversefrom(z.z, n))
reverse(z::Zip1) = Zip1(reverse(z.a))
reverse(z::Union{Zip,Zip2}) = reversefrom(z, length(z)) but to be useful, |
@stevengj It is hard to think of an iterator one can reverse efficiently from its last element, but not from an earlier element. |
@mschauer, the problem is precisely that you can't do this from the existing iteration protocol functions, so each iterator would have to implement more functions for it to work.
|
Yes, I know that |
I think it adds too much complexity to require every iterator to support |
Hm, it is not needed to require every iterator to support
implements a fallback which also just throws an error if a special reversefrom is not implemented strictly extending the alternative of throwing an error at the cost of complexity of some ten lines. |
For this functionality to actually be useful, a fair number of iterators will need to implement new methods, which is a lot of code devoted to a corner case of questionable utility. |
Yes, I wrote above "but to be useful, reversefrom(it, n::Integer) needs to defined for some more iterators". I thought of |
If anybody else is interested in having this, they can create a PR from https://github.com/JuliaLang/julia/compare/master...mschauer:reverse?expand=1 |
Given reverse(v [, start=firstindex(v) [, stop=lastindex(v) ]] )
Return a copy of v reversed from start to stop. See also Iterators.reverse for reverse-order iteration without
making a copy, and in-place reverse!. I think the current behavior is better classified as a bug. Throwing an error is probably a bug too, but at least it's not the wrong answer. |
…r equality (#50435) fixes #45085, fixes #25583, as per suggested by @Moelf Despite the fact that this might cause code to fail that previously worked, I think this is a bugfix not a breaking change. In particular, `Iterators.reverse` says: > Given an iterator itr, then reverse(itr) is an iterator over the same collection but in the reverse order And in many cases, the previous behavior of `reverse(::Zip)` would _not_ return "the same collection"
In the following example, it sounds like a bug that
reverse
assumes that the last element of1:10
goes with the last element of1:2
. This can give misleading results. If possible it would make sense to throw an error in these cases.The text was updated successfully, but these errors were encountered: