diff --git a/docs/src/api.md b/docs/src/api.md index 0ce5e97..e485a53 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -15,6 +15,7 @@ CircShiftedVector lag lead ShiftedArrays.circshift +ShiftedArrays.diff ``` ## FFT shifts diff --git a/docs/src/index.md b/docs/src/index.md index 2245371..c598dbd 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -87,7 +87,9 @@ julia> ShiftedArray([1.2, 3.1, 4.5], 1, default = NaN)[-2:3] ## Shifting the data -Using the `ShiftedArray` type, this package provides two operations for lazily shifting vectors: `lag` and `lead`. +Using the `ShiftedArray` type, this package provides two operations for lazily shifting arrays: `lag` and `lead`. It also provides +the function `ShiftedArrays.diff` for calculating the differences +between elements in arrays. ```julia julia> v = [1, 3, 5, 4]; @@ -127,6 +129,19 @@ julia> lead(v) missing ``` +`diff` is an analogue for `v .- lag(v)` + +```julia +julia> v = [1, 3, 5, 4]; + +julia> ShiftedArrays.diff(v) +4-element Vector{Union{Missing, Int64}}: + missing + 2 + 2 + -1 +``` + ## Shifting the data circularly Julia Base provides a function `circshift` to shift the data circularly. However this function diff --git a/src/ShiftedArrays.jl b/src/ShiftedArrays.jl index a97c814..6f9022a 100644 --- a/src/ShiftedArrays.jl +++ b/src/ShiftedArrays.jl @@ -4,6 +4,7 @@ import Base: checkbounds, getindex, setindex!, parent, size export ShiftedArray, ShiftedVector, shifts, default export CircShiftedArray, CircShiftedVector export lag, lead +# ShiftedArrays.diff unexported due to collision include("shiftedarray.jl") include("circshiftedarray.jl") diff --git a/src/lag.jl b/src/lag.jl index b9aa558..6c2e96a 100644 --- a/src/lag.jl +++ b/src/lag.jl @@ -97,3 +97,49 @@ julia> s = lead(v, (0, 2)) ``` """ lead(v::AbstractArray, n = 1; default = missing) = ShiftedArray(v, map(-, n); default = default) + + +""" + ShiftedArrays.diff(v::AbstractArray, n = 1; default = missing) + +Return a freshly allocated array of the differences between elements +in the array. The second argument gives the amount to shift in each dimension. +If it is an integer, it is assumed to refer to the first dimension. +`default` specifies a default value when you are out of bounds. + +## Examples + +```jldoctest diff +julia> v = [1, 3, 5, 4]; + +julia> ShiftedArrays.diff(v) +4-element Vector{Union{Missing, Int64}}: + missing + 2 + 2 + -1 + +julia> w = 1:2:9 +1:2:9 + +julia> s = ShiftedArrays.diff(w, 2) +5-element Vector{Union{Missing, Int64}}: + missing + missing + 4 + 4 + 4 + +julia> v = reshape(1:16, 4, 4); + +julia> s = ShiftedArrays.diff(v, (0, 2)) +4×4 Matrix{Union{Missing, Int64}}: + missing missing 8 8 + missing missing 8 8 + missing missing 8 8 + missing missing 8 8 +""" +function diff(v::AbstractArray, n = 1; default = missing) + l = lag(v, n; default = default) + v .- l +end diff --git a/test/runtests.jl b/test/runtests.jl index 2155778..b1eb455 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -126,9 +126,13 @@ end diff = v .- lag(v) @test isequal(diff, [missing, 2, 5, 4]) + @test isequal(diff, ShiftedArrays.diff(v)) + diff2 = v .- lag(v, 2) @test isequal(diff2, [missing, missing, 7, 9]) + @test isequal(diff2, ShiftedArrays.diff(v)) + @test all(lag(v, 2, default = -100) .== coalesce.(lag(v, 2), -100)) diff = v .- lead(v)