-
Notifications
You must be signed in to change notification settings - Fork 12
Support deleteat!
#12
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
Conversation
Codecov Report
@@ Coverage Diff @@
## master #12 +/- ##
==========================================
+ Coverage 92.30% 93.75% +1.44%
==========================================
Files 1 1
Lines 26 32 +6
==========================================
+ Hits 24 30 +6
Misses 2 2
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
Some thoughts: (unique ∘ sort ∘ map)(i -> mod(i, eachindex(a.data)), inds) can be made much faster for a mutable type (unique! ∘ sort! ∘ map)(i -> mod(i, eachindex(a.data)), inds) but it'll fail on say a (unique!! ∘ sort!! ∘ map)(i -> mod(i, eachindex(a.data)), inds) and have the best of both worlds quite easily. An even heavier dependancy, Trandsducers.jl might be able to fuse these operations in a more efficient manner too. |
I was actually planning on implementing that this weekend, thank you very much! |
I am not a fan of depending on random packages for functionality like this, especially not with a package this small. Ideally, this package would have no dependencies, the dependency on |
While I definitely disagree with this attitude, that's fully your prerogative and it's why I wrote this PR with the naive, out-of-place implementation initially. I can add some methods for collection types that are known to be mutable which take advantage of mutation if you'd like, or can just leave it as is. |
src/CircularArrays.jl
Outdated
end | ||
|
||
function Base.deleteat!(a::CircularVector, i::Integer) | ||
deleteat!(a.data, mod(i, eachindex(a.data))) |
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 any reason not to do this? Would be more consistent with other methods.
deleteat!(a.data, mod(i, eachindex(a.data))) | |
deleteat!(a.data, mod1(i, length(a.data))) |
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.
Mine should work regardless of the index scheme a
uses, whereas yours would assume a
is always indexed from 1:N
. Since CircularArray
can store any abstract vector, I think it's good to be generic.
I would have included a OffsetArrays.jl testcase for this, but offsetarrays doesn't actually support deleteat!
:(
src/CircularArrays.jl
Outdated
@@ -65,4 +65,14 @@ function Base.showarg(io::IO, arr::CircularArray, toplevel) | |||
# toplevel && print(io, " with eltype ", eltype(arr)) | |||
end | |||
|
|||
function Base.deleteat!(a::CircularVector, inds) | |||
deleteat!(a.data, (unique ∘ sort ∘ map)(i -> mod(i, eachindex(a.data)), inds)) |
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 sadly fails if inds
is a Tuple
since sort
isn't implemented for Tuples. It should be sort ∘ unique ∘ map
, probably.
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 further managed to slightly improve performance by making this line more consistent with the rest, probably because of the removal of eachindex
.
deleteat!(a.data, (unique ∘ sort ∘ map)(i -> mod(i, eachindex(a.data)), inds)) | |
deleteat!(a.data, sort(unique(mod1.(inds, length(a.data))))) |
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.
Mhm, that's unfortunate that sort
isn't supported for Tuple
but makes sense. We could just handle Tuple
separately I suppose.
Using unique
before sort
has it's own problems because we'd end up allocating an array...
julia> unique((1,2,3))
3-element Vector{Int64}:
1
2
3
Could just not do the unique
or sort
and say it's the user's fault if they give indices that cause an error (this is what Base
does, but it's easier to screw up the ordering here due to circularity)
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.
What if we do sort! ∘ unique
? If unique
always returns a mutable array, this should have the same number of allocations as before, or fewer.
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.
Good point!
Okay, so now we have an escape hatch for julia> f(v) = firstindex(v) === 1 ? 1 : 2
f (generic function with 1 method)
julia> code_typed(f, (Vector{Int},))
1-element Vector{Any}:
CodeInfo(
1 ─ Base.arraysize(v, 1)::Int64
└── return 1
) => Int64 I also switched the order of the |
Makes me wonder if the shortcut to code_typed(deleteat!, (CircularArray{Int64,1,Array{Int64,1}}, Tuple{Int64,Int64,Int64})) for two different implementations function Base.deleteat!(a::CircularVector, inds)
jnds = firstindex(a) === 1 ? mod1.(inds, length(a)) : map(i -> mod(i, eachindex(a.data)), inds)
deleteat!(a.data, sort!(unique(jnds)))
a
end
# ====
function Base.deleteat!(a::CircularVector, inds)
deleteat!(a.data, sort!(unique(map(i -> mod(i, eachindex(a.data)), inds))))
a
end
|
The problem with using
|
Testing further, forcing linear indexing with |
This is technically true, but in practice, an One thing we could do is just put a note in a docstring or something and say that if
I suspect that if some wacky type is a |
This looks good to me now. I'll merge this and add the |
With this change
Closes #11