Iterators.Reverse type for reverse-order iteration#24187
Iterators.Reverse type for reverse-order iteration#24187ararslan merged 2 commits intoJuliaLang:masterfrom
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.
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.
Same question regarding collect. Seems odd for strings. (GitHub ate my previous comment.)
There was a problem hiding this comment.
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.
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.
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.
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.
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.
Okay. I trust your judgement for whatever the best approach is here, just thought I'd point it out.
| Base.Iterators.product | ||
| Base.Iterators.flatten | ||
| Base.Iterators.partition | ||
| Base.Iterators.filter |
There was a problem hiding this comment.
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.
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.
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 asstartetcetera have been defined forReverse{T}. Initially, I've implemented reverse iterators forAbstractArray,AbstractString,Tuple,Generator, and some other iterator types (zip, product, etc)..I useReversedand notReversebecause the latter name is already used forBase.Order.Reverse.To do: