From c2cd601f01849aca85c843f3eb277a0342fee0a6 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 26 Feb 2020 15:41:26 -0500 Subject: [PATCH] Allow 2-arg splice! on arbitrary index iterables (#34524) We have deleteat!(vec::Vector, itr), but it returns the modified vector. If you instead want to obtain the delted elements, there is splice!(::Vector, ::UnitRange) as a special case of the three-argument version that inserts additional elements where the old ones were deleted. However, these is no two argument splice! for arbitrary iterables, so probably the best way to write that currently is: ``` inds = collect(itr) vals = A[inds] deleteat!(A, inds) vals ``` which is both less efficient and more verbose than ideal. I'm wondering if perhaps deleteat! should have been returning the deleted elements, but that's not a change we can make in 1.x. Instead, I'm proposing here to extend the 2 argument (but not the 3 argument for obvious reasons) variant of splice! to arbitrary iterables. --- base/array.jl | 9 ++++++++- test/arrayops.jl | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/base/array.jl b/base/array.jl index 9fd36c5dfd715..2a776ae1e9df7 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1273,12 +1273,16 @@ Stacktrace: deleteat!(a::Vector, inds) = _deleteat!(a, inds) deleteat!(a::Vector, inds::AbstractVector) = _deleteat!(a, to_indices(a, (inds,))[1]) -function _deleteat!(a::Vector, inds) +struct Nowhere; end +push!(::Nowhere, _) = nothing + +function _deleteat!(a::Vector, inds, dltd=Nowhere()) n = length(a) y = iterate(inds) y === nothing && return a n == 0 && throw(BoundsError(a, inds)) (p, s) = y + p <= n && push!(dltd, @inbounds a[p]) q = p+1 while true y = iterate(inds, s) @@ -1295,6 +1299,7 @@ function _deleteat!(a::Vector, inds) @inbounds a[p] = a[q] p += 1; q += 1 end + push!(dltd, @inbounds a[i]) q = i+1 end while q <= n @@ -1444,6 +1449,8 @@ function splice!(a::Vector, r::UnitRange{<:Integer}, ins=_default_splice) return v end +splice!(a::Vector, inds) = (dltds = eltype(a)[]; _deleteat!(a, inds, dltds); dltds) + function empty!(a::Vector) _deleteend!(a, length(a)) return a diff --git a/test/arrayops.jl b/test/arrayops.jl index 4f55a34c51fad..aa04aa0dfbac1 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1342,6 +1342,7 @@ end @test a == [acopy[1:(first(idx)-1)]; repl; acopy[(last(idx)+1):end]] end end + @test splice!([4,3,2,1], [2, 4]) == [3, 1] end @testset "filter!" begin