Skip to content

Commit 4cdcdb8

Browse files
authored
add keepat! (the opposite of deleteat!) (#36229)
1 parent 97d5f6a commit 4cdcdb8

File tree

5 files changed

+68
-0
lines changed

5 files changed

+68
-0
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ New library functions
4747

4848
* Two argument methods `findmax(f, domain)`, `argmax(f, domain)` and the corresponding `min` versions ([#27613]).
4949
* `isunordered(x)` returns true if `x` is value that is normally unordered, such as `NaN` or `missing`.
50+
* New `keepat!(vector, inds)` function which is the inplace equivalent of `vector[inds]`
51+
for a list `inds` of integers ([#36229]).
5052
* New macro `Base.@invokelatest f(args...; kwargs...)` provides a convenient way to call `Base.invokelatest(f, args...; kwargs...)` ([#37971])
5153
* Two arguments method `lock(f, lck)` now accepts a `Channel` as the second argument. ([#39312])
5254
* New functor `Returns(value)`, which returns `value` for any arguments ([#39794])

base/abstractarray.jl

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2918,3 +2918,46 @@ function rest(a::AbstractArray{T}, state...) where {T}
29182918
sizehint!(v, length(a))
29192919
return foldl(push!, Iterators.rest(a, state...), init=v)
29202920
end
2921+
2922+
2923+
## keepat! ##
2924+
2925+
"""
2926+
keepat!(a::AbstractVector, inds)
2927+
2928+
Remove the items at all the indices which are not given by `inds`,
2929+
and return the modified `a`.
2930+
Items which are kept are shifted to fill the resulting gaps.
2931+
2932+
`inds` must be an iterator of sorted and unique integer indices.
2933+
See also [`deleteat!`](@ref).
2934+
2935+
!!! compat "Julia 1.7"
2936+
This function is available as of Julia 1.7.
2937+
2938+
# Examples
2939+
```jldoctest
2940+
julia> keepat!([6, 5, 4, 3, 2, 1], 1:2:5)
2941+
3-element Array{Int64,1}:
2942+
6
2943+
4
2944+
2
2945+
```
2946+
"""
2947+
function keepat!(a::AbstractVector, inds)
2948+
local prev
2949+
i = firstindex(a)
2950+
for k in inds
2951+
if @isdefined(prev)
2952+
prev < k || throw(ArgumentError("indices must be unique and sorted"))
2953+
end
2954+
ak = a[k] # must happen even when i==k for bounds checking
2955+
if i != k
2956+
@inbounds a[i] = ak # k > i, so a[i] is inbounds
2957+
end
2958+
prev = k
2959+
i = nextind(a, i)
2960+
end
2961+
deleteat!(a, i:lastindex(a))
2962+
return a
2963+
end

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ export
504504
count,
505505
delete!,
506506
deleteat!,
507+
keepat!,
507508
eltype,
508509
empty!,
509510
empty,

doc/src/base/collections.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ Base.pushfirst!
273273
Base.popfirst!
274274
Base.insert!
275275
Base.deleteat!
276+
Base.keepat!
276277
Base.splice!
277278
Base.resize!
278279
Base.append!

test/abstractarray.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,3 +1364,24 @@ end
13641364
@test [v v;;; fill(v, 1, 2)] == fill(v, 1, 2, 2)
13651365
end
13661366
end
1367+
1368+
@testset "keepat!" begin
1369+
a = [1:6;]
1370+
@test a === keepat!(a, 1:5)
1371+
@test a == 1:5
1372+
@test keepat!(a, [2, 4]) == [2, 4]
1373+
@test isempty(keepat!(a, []))
1374+
1375+
a = [1:6;]
1376+
@test_throws BoundsError keepat!(a, 1:10) # make sure this is not a no-op
1377+
@test_throws BoundsError keepat!(a, 2:10)
1378+
@test_throws ArgumentError keepat!(a, [2, 4, 3])
1379+
1380+
b = BitVector([1, 1, 1, 0, 0])
1381+
@test b === keepat!(b, 1:5)
1382+
@test b == [1, 1, 1, 0, 0]
1383+
@test keepat!(b, 2:4) == [1, 1, 0]
1384+
@test_throws BoundsError keepat!(a, -1:10)
1385+
@test_throws ArgumentError keepat!(a, [2, 1])
1386+
@test isempty(keepat!(a, []))
1387+
end

0 commit comments

Comments
 (0)