-
-
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
Updated filter!
to take an AbstractVector
vs a Vector
.
#21417
Conversation
base/array.jl
Outdated
@@ -1805,7 +1805,7 @@ julia> filter(isodd, a) | |||
""" | |||
filter(f, As::AbstractArray) = As[map(f, As)::AbstractArray{Bool}] | |||
|
|||
function filter!(f, a::Vector) | |||
function filter!(f, a::AbstractVector) | |||
insrt = 1 |
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 will only work for 1-based linear indexing arrays. Would be better to iterate over eachindex(a)
.
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.
Alright, I've made that change and added some tests to make sure it works. Is there an array type in Base that I can test against which doesn't use 1-based linear indexing?
b3e6898
to
a6c6e97
Compare
test/arrayops.jl
Outdated
filter!(x -> x > 5, a) | ||
|
||
# different subtype of AbstractVector | ||
@test a == collect(6:10) |
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.
Shouldn't this line be in the previous block?
b18bea3
to
72dd093
Compare
@tkelman and @nalimilan: Are there any other changes you'd like made or any other tests you'd like added before this can be merged? |
end | ||
end | ||
deleteat!(a, insrt:length(a)) | ||
|
||
deleteat!(a, i:last(idx)) |
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 wonder whether it could be more efficient to do resize!(a, len)
, even though this implies computing len
. Not for this PR though.
base/array.jl
Outdated
function filter!(f, a::AbstractVector) | ||
idx = eachindex(a) | ||
state = start(idx) | ||
(i, state) = next(idx, state) |
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.
Sorry, I had missed this: you need a done(idx, state) && return a
check before this for empty arrays. The tests didn't catch this since the implementation for Array
doesn't throw an error (and just returns state+1
), but in general it could fail.
BTW, you can remove parentheses on LHS for tuple assignment (here and below).
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.
@nalimilan The next
behaviour was kind of intentional here as we want i
to be at state+1
passed the end of the new last index when we get to the deleteat!
. I suppose a done(idx, state)
or isempty(a)
check would avoid needing to call deleteat!
, but we still run into the issue of going passed the end of the array with the next(idx, state)
call in the for loop. This issue would probably be better circumvented with Keno's revised iteration protocol julep.
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.
Since you just need to return immediately when the input is empty, I don't see why deletat!
enters the picture at all.
|
… `OffsetArray` tests.
cfc0674
to
ac07ec5
Compare
@tkelman Thanks, that's exactly what I was looking for. |
base/array.jl
Outdated
a[insrt] = acurr | ||
insrt += 1 | ||
function filter!(f, a::AbstractVector) | ||
if !isempty(a) |
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.
isempty(a) && return a
would be better style IMHO since it avoids wrapping the whole body inside the condition.
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 get not wanting to wrap the entire thing in an if
, but I generally try to avoid putting multiple return statements in a function.
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.
That's a common style in the Julia code base for simple initial checks like this.
@@ -198,6 +198,24 @@ end | |||
val | |||
end | |||
|
|||
@inline function Base.deleteat!(A::OffsetArray, i::Int) | |||
checkbounds(A, i) |
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.
A @boundscheck
annotation would be useful here and below.
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.
Or maybe you don't need this and offset
could just do it for you? @timholy?
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.
While not a big deal, changing the bounds checking in the OffsetArray
code feels a little outside the scope of this PR. As it stands, this has progressed from a 1 word change to partly rewriting filter!
, adding tests and extending the OffsetArray
s code.
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, my suggestion aimed at requiring less changes, not more. If that involves doing changes elsewhere then I agree it's not the place to do it.
Anyway, just add the @boundscheck
annotations and it should be good to merge, though a quick review of the OffsetArray
parts by @timholy would be nice.
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 still think making a separate PR to put all the checkbounds
calls for OffsetArray
s inside an @boundscheck
would keep things more organized and consistent.
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.
@nalimilan I don't think it makes sense to add @boundscheck
annotations in one place but not the other very similar cases in the same file for the same type. I think those changes would be best made all at once in a separate PR.
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.
Fine with me. I hadn't realized the existing functions didn't use this.
I just realized that the new function relies on the assumption that one can index an |
@nalimilan It doesn't make that assumption. It iterates over each index and indexes with those. |
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'll merge this tomorrow
Allow
filter!
to operate onAbstractVector
s. This pushes the requirement to whether or notdeleteat!
is implemented for the array. My use case is that I wantfilter!
to work onNullableArray
s andDataArray
s, which already havedeleteat!
implemented.