Skip to content

Add a keyword argument to diff which preserves length #42509

@pdeffebach

Description

@pdeffebach

Currently Base.diff(x) produces a new vector with length length(x) - 1.

This is often annoying when working with tabular data, since you cannot do

df.x_diff = diff(df.x)

@nalimilan recommended a keyword argument to Base.diff, which allows for pre-pending a default value such that length, and shape more generally in the case of matrices and other arrays, is preserved.

Given the discussion in the issue below, I propose keyword arguments fillfirst and filllast which indicate the value appended to the array.

julia> begin 
       function newdiff(a::AbstractArray{T,N}; dims::Integer=1, 
                        fillfirst=nothing, 
                        filllast=nothing) where {T,N}
           Base.require_one_based_indexing(a)
           1 <= dims <= N || throw(ArgumentError("dimension $dims out of range (1:$N)"))
       
           r = axes(a)
           r0 = ntuple(i -> i == dims ? UnitRange(1, last(r[i]) - 1) : UnitRange(r[i]), N)
           r1 = ntuple(i -> i == dims ? UnitRange(2, last(r[i])) : UnitRange(r[i]), N)
           if fillfirst !== nothing  
               out = similar(a, Union{eltype(a), typeof(fillfirst)})
               out .= fillfirst
               out[r1...] .= view(a, r1...) .- view(a, r0...)
               return out
           elseif filllast !== nothing  
               out = similar(a, Union{eltype(a), typeof(filllast)})
               out .= filllast
               out[r0...] .= view(a, r1...) .- view(a, r0...)
               return out
           else
               view(a, r0...)
               return view(a, r1...) .- view(a, r0...)
           end
       end
       end
newdiff (generic function with 1 method)

julia> x = collect(1:5) # separate method for ranges;

julia> newdiff(x)
4-element Vector{Int64}:
 1
 1
 1
 1

julia> newdiff(x; fillfirst=0)
5-element Vector{Int64}:
 0
 1
 1
 1
 1

julia> newdiff(x; filllast=0)
5-element Vector{Int64}:
 1
 1
 1
 1
 0

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureIndicates new feature / enhancement requests

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions