-
-
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 type for reverse-order iteration #24187
Conversation
Any reason not to return the original object instead? EDIT: actually, the current result above cannot even be iterated over, throwing Also, |
Should probably add definitions like Reversed(r::Reversed) = r.iter
reverse(r::Reversed) = copy(r.iter) |
base/abstractarray.jl
Outdated
Reversed(R::AbstractRange) = reverse(R) # copying ranges is cheap | ||
Reversed(G::Generator) = Generator(G.f, Reversed(G.iter)) | ||
Reversed(r::Reversed) = r.iter | ||
reverse(r::Reversed) = collect(r.iter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using collect
is kind of weird for strings, isn't it? Or am I missing something?
Would it be worth adding something like getindex(r::Reversed, i::Integer) = reverseind(r.iter, Int(i)) ? |
@ararslan, I thought about adding However, I'm still not sold on |
I would have like to have used lower-case for the function, analogous to Any other bikeshedding on the name? |
base/iterators.jl
Outdated
Reversed(R::AbstractRange) = reverse(R) # copying ranges is cheap | ||
Reversed(G::Generator) = Generator(G.f, Reversed(G.itr)) | ||
Reversed(r::Reversed) = r.itr | ||
reverse(r::Reversed) = collect(r.itr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question regarding collect
. Seems odd for strings. (GitHub ate my previous comment.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this odd for strings? Reversed{<:String}
is an iterator over characters, so should reverse(r)
on it be the same as reverse(collect(r))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have expected that since the underlying object being iterated is a string, unwrapping the Reversed
wrapper would give you back the string, just as reverse(::String)
gives you a string.
Calling it |
Note: 44e383f is a bugfix that should be backported to 0.6. So, that commit should not be squashed with the others when/if this PR is merged. |
I don't think calling it |
I disagree; I think the difference between |
Using caps does emphasize that it is a wrapper type (a “noun”) rather than a transformation of the underlying data (a “verb”). Of course, one could similarly question why we don’t capitalize |
In the very specific case of |
We already have |
Note that we actually once did have a |
Probably we should have a |
I think one generally wants a similar kind of collection when reversing, so that fallback might need some tweaking. In general, I suspect that having a general fallback for reversal is not worth it and we should just supply the methods where we know what to do and let people fill in the rest. |
@StefanKarpinski, my objection is that it seems really weird and surprising for a collection to support Imagine the user questions: "How do I reverse the order of this collection? Another way of saying it: this reduces the number of methods a collection needs to implement. If reverse-order iteration is worthwhile, so you implement |
@nalimilan's |
doc/src/manual/interfaces.md
Outdated
by iterating over `Reversed(iterator)`. [`Reversed`](@ref) is just a thin wrapper | ||
around our collection; to actually support reverse-order iteration, an iterator | ||
type `T` needs to implement `start`, `next`, and `done` methods for `Reversed{T}`. | ||
(Given `r::Reversed{T}`, the underling iterator of type `T` is `Reversed(r)`.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we just document r.itr
instead of suggesting Reversed(r)
or Iterators.reverse(r)
or whatever we decide to call it?
r.itr
is a bit more transparent and convenient, but it does expose the internal field name.
@stevengj, I'm willing to live with a few awkward questions about missing features in 1.0 rather than adding new, half-baked functionality that we then have to live with for a decade, no matter how wrong it turns out we are about how it behaves. |
Okay, I removed the |
base/iterators.jl
Outdated
@propagate_inbounds next(A::Reverse{<:AbstractArray}, i) = ((idx, s) = next(i[1], i[2]); (A.itr[idx], (i[1], s))) | ||
@propagate_inbounds done(A::Reverse{<:AbstractArray}, i) = done(i[1], i[2]) | ||
|
||
Reverse(R::AbstractRange) = Base.reverse(R) # copying ranges is cheap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kind of weird in that you're asking for a lazy reverse but getting a new range back instead of a Reverse
iterator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ranges are already lazy, so it seems silly to define Reverse
iteration methods for ranges.
But I guess I can now change this to a method of Iterators.reverse
instead of Reverse
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I trust your judgement for whatever the best approach is here, just thought I'd point it out.
@@ -12,4 +12,6 @@ Base.Iterators.repeated | |||
Base.Iterators.product | |||
Base.Iterators.flatten | |||
Base.Iterators.partition | |||
Base.Iterators.filter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some reason that Iterators.filter
was not listed here previously? It seemed like an oversight.
Also, the ordering of methods here seems kind of random; is it automatically sorted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I think it was an oversight. Documenter doesn't do any sorting of methods—they appear in the output in the same order as you write them AFAIK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, now that I look more closely at the order, it seems like they have been somewhat topically sorted, so I think the order is fine as-is.
Yeah, there have been a few issues with Circle, particularly x86-64, lately. |
For comparison, the Python |
Rebased to fix conflict. Note: if/when this is merged, don't squash since the bugfix commit should be backported. |
It looks like this was squashed, but wasn't this supposed to be not squashed? |
It was not squashed. |
Ok, sorry for the noise! |
This PR closes #23972 by adding a new
Reversed{T}
Iterators.Reverse{T}
wrapper type for reverse-order iteration.The basic idea (suggested by @Keno) is that you can just loop over
Iterators.reverse(iter)
and it will go in reverse order, as long asstart
etcetera have been defined forReverse{T}
. Initially, I've implemented reverse iterators forAbstractArray
,AbstractString
,Tuple
,Generator
, and some other iterator types (zip, product, etc)..I useReversed
and notReverse
because the latter name is already used forBase.Order.Reverse
.To do: