Skip to content
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

Merged
merged 6 commits into from
Apr 25, 2017

Conversation

rofinn
Copy link
Contributor

@rofinn rofinn commented Apr 17, 2017

Allow filter! to operate on AbstractVectors. This pushes the requirement to whether or not deleteat! is implemented for the array. My use case is that I want filter! to work on NullableArrays and DataArrays, which already have deleteat! implemented.

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
Copy link
Member

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).

Copy link
Contributor Author

@rofinn rofinn Apr 19, 2017

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?

@tkelman tkelman added the needs tests Unit tests are required for this change label Apr 17, 2017
test/arrayops.jl Outdated
filter!(x -> x > 5, a)

# different subtype of AbstractVector
@test a == collect(6:10)
Copy link
Member

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?

@rofinn
Copy link
Contributor Author

rofinn commented Apr 20, 2017

@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?

@tkelman tkelman removed the needs tests Unit tests are required for this change label Apr 20, 2017
end
end
deleteat!(a, insrt:length(a))

deleteat!(a, i:last(idx))
Copy link
Member

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)
Copy link
Member

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).

Copy link
Contributor Author

@rofinn rofinn Apr 21, 2017

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.

Copy link
Member

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.

@tkelman
Copy link
Contributor

tkelman commented Apr 21, 2017

@timholy would probably suggest testing against a non-1-indexed array type from TestHelpers, as well

@rofinn
Copy link
Contributor Author

rofinn commented Apr 21, 2017

@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)
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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)
Copy link
Member

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.

Copy link
Member

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?

Copy link
Contributor Author

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 OffsetArrays code.

Copy link
Member

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.

Copy link
Contributor Author

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 OffsetArrays inside an @boundscheck would keep things more organized and consistent.

Copy link
Contributor

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.

Copy link
Member

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.

@nalimilan
Copy link
Member

I just realized that the new function relies on the assumption that one can index an AbstractArray with the iteration state. That's fine in this case since this is true for Base array types and because the new method is a strict improvement over the current state, but we should really do something about this. The same issue was raised in #18668 (comment).

@iamed2
Copy link
Contributor

iamed2 commented Apr 23, 2017

@nalimilan It doesn't make that assumption. It iterates over each index and indexes with those.

Copy link
Member

@omus omus left a 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

@omus omus merged commit 2c704d1 into JuliaLang:master Apr 25, 2017
@omus omus deleted the filter-on-abstract-vector branch April 25, 2017 14:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants