purrr
purrr copied to clipboard
An accumulate-style function but without recursivity?
This issue ocurr to me as I do Structural Decomposition Analysis (using Input-Output matrices and etecetera) , and found no function like this in the purrr package and no issue about this here. Nevertheless, I will try to make my point the simplier the possible. What I want is to apply functions using 2 consecutive elements of a vectors without being recursive as accumulate
is.
Suppose you have a vector, inputVec
, of length n
. In this case, let's make:
set.seed(1)
inputVec <- runif(10)
inputVec
#> [1] 0.26550866 0.37212390 0.57285336 0.90820779 0.20168193 0.89838968
#> [7] 0.94467527 0.66079779 0.62911404 0.06178627
If you run accumulate(inputVec, sum)
you are going to get a vector like:
library(purrr)
purrr::accumulate(inputVec, sum)
#> [1] 0.2655087 0.6376326 1.2104859 2.1186937 2.3203756 3.2187653 4.1634406
#> [8] 4.8242384 5.4533524 5.5151387
The third element, 1.2104859
, is the result of sum( sum(inputVec[1], inputVec[2]), inputVec[3])
. This happens because accumulate is recursive (it uses its own outputs). But lets suppose you don't want this recursivity. Suppose you want to use only the original elements of inputVec
as inputs. In our example, this would be c(sum(inputVec[1], inputVec[2]), sum(inputVec[2], inputVec[3]), ....,sum(inputVec[9], inputVec[10]))
.
One can notice that this take a vector of length n and returns one of lenght n-1. Combining purrr:map2
and rlang::exec
, I created a function that I believe that should solve this problem, I called it innermap
:
library(rlang, warn,conflicts = F)
innermap <- function(input, .f0){
require(rlang)
require(purrr)
.output <- map2(c(1:(length(input)-1)), c(2:length(input)),
function(x1,x2) rlang::exec(.f0, input[x1], input[x2]))
return(.output)
}
The result we got is:
innermap(inputVec, sum) %>% unlist()
#> [1] 0.6376326 0.9449773 1.4810612 1.1098897 1.1000716 1.8430650 1.6054731
#> [8] 1.2899118 0.6909003
It also works in other situations:
innermap(letters, paste0) %>% unlist()
#> [1] "ab" "bc" "cd" "de" "ef" "fg" "gh" "hi" "ij" "jk" "kl" "lm" "mn" "no" "op"
#> [16] "pq" "qr" "rs" "st" "tu" "uv" "vw" "wx" "xy" "yz"
I believe a function like that, done by true professionals, could be a good addition to the purrr package.
I created a package with functions that would be what I think nice additions (I didn't make them using C++, so maybe there are some possible perfomance gains here).
https://github.com/MarceloRTonon/innermap
A more compact purrr solution to the described problem would be
map2_dbl(head(input, -1L), tail(input, -1L), sum)
I think slider::slide_*()
(with parameters .before = 1, .after = 0
) can provide the desired output.
This definitely sounds more like a job for slider than purrr.