Skip to content

Commit

Permalink
add keepat! (the opposite of deleteat!) (#36229)
Browse files Browse the repository at this point in the history
  • Loading branch information
rfourquet authored May 27, 2021
1 parent 97d5f6a commit 4cdcdb8
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 0 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ New library functions

* Two argument methods `findmax(f, domain)`, `argmax(f, domain)` and the corresponding `min` versions ([#27613]).
* `isunordered(x)` returns true if `x` is value that is normally unordered, such as `NaN` or `missing`.
* New `keepat!(vector, inds)` function which is the inplace equivalent of `vector[inds]`
for a list `inds` of integers ([#36229]).
* New macro `Base.@invokelatest f(args...; kwargs...)` provides a convenient way to call `Base.invokelatest(f, args...; kwargs...)` ([#37971])
* Two arguments method `lock(f, lck)` now accepts a `Channel` as the second argument. ([#39312])
* New functor `Returns(value)`, which returns `value` for any arguments ([#39794])
Expand Down
43 changes: 43 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2918,3 +2918,46 @@ function rest(a::AbstractArray{T}, state...) where {T}
sizehint!(v, length(a))
return foldl(push!, Iterators.rest(a, state...), init=v)
end


## keepat! ##

"""
keepat!(a::AbstractVector, inds)
Remove the items at all the indices which are not given by `inds`,
and return the modified `a`.
Items which are kept are shifted to fill the resulting gaps.
`inds` must be an iterator of sorted and unique integer indices.
See also [`deleteat!`](@ref).
!!! compat "Julia 1.7"
This function is available as of Julia 1.7.
# Examples
```jldoctest
julia> keepat!([6, 5, 4, 3, 2, 1], 1:2:5)
3-element Array{Int64,1}:
6
4
2
```
"""
function keepat!(a::AbstractVector, inds)
local prev
i = firstindex(a)
for k in inds
if @isdefined(prev)
prev < k || throw(ArgumentError("indices must be unique and sorted"))
end
ak = a[k] # must happen even when i==k for bounds checking
if i != k
@inbounds a[i] = ak # k > i, so a[i] is inbounds
end
prev = k
i = nextind(a, i)
end
deleteat!(a, i:lastindex(a))
return a
end
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ export
count,
delete!,
deleteat!,
keepat!,
eltype,
empty!,
empty,
Expand Down
1 change: 1 addition & 0 deletions doc/src/base/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ Base.pushfirst!
Base.popfirst!
Base.insert!
Base.deleteat!
Base.keepat!
Base.splice!
Base.resize!
Base.append!
Expand Down
21 changes: 21 additions & 0 deletions test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1364,3 +1364,24 @@ end
@test [v v;;; fill(v, 1, 2)] == fill(v, 1, 2, 2)
end
end

@testset "keepat!" begin
a = [1:6;]
@test a === keepat!(a, 1:5)
@test a == 1:5
@test keepat!(a, [2, 4]) == [2, 4]
@test isempty(keepat!(a, []))

a = [1:6;]
@test_throws BoundsError keepat!(a, 1:10) # make sure this is not a no-op
@test_throws BoundsError keepat!(a, 2:10)
@test_throws ArgumentError keepat!(a, [2, 4, 3])

b = BitVector([1, 1, 1, 0, 0])
@test b === keepat!(b, 1:5)
@test b == [1, 1, 1, 0, 0]
@test keepat!(b, 2:4) == [1, 1, 0]
@test_throws BoundsError keepat!(a, -1:10)
@test_throws ArgumentError keepat!(a, [2, 1])
@test isempty(keepat!(a, []))
end

0 comments on commit 4cdcdb8

Please sign in to comment.