How can I use accumulate like reduce2 function in purrr?
Asked Answered
E

3

6

I would like to use the accumulate function with two input vectors and the reduce2 function. The documentation for accumulate implies that two input vectors can be given and that accumulate can work with reduce2. However, I am having trouble.

Here is an example, inspired by the documentation from reduce2.

This is the example from reduce2

> paste2 <- function(x, y, sep = ".") paste(x, y, sep = sep)
> letters[1:4] %>% reduce2(.y=c("-", ".", "-"), paste2)
[1] "a-b.c-d"

Here are several attempts to use accumulate similarly to reduce2. None properly iterate through both letters[1:4] and c("-",".","-").

> letters[1:4] %>% accumulate(.y=c("-", ".", "-"),paste2)
Error in .f(x, y, ...) : unused argument (.y = c("-", ".", "-"))

> letters[1:4] %>% accumulate(c("-", ".", "-"),paste2)
[[1]]
[1] "a"

[[2]]
NULL

> letters[1:4] %>% accumulate(sep=c("-", ".", "-"),paste2)
[1] "a"       "a-b"     "a-b-c"   "a-b-c-d"

How would I use accumulate to see the intermediate results given by the reduce2 example?

Eniwetok answered 11/5, 2018 at 15:43 Comment(0)
A
1

It is possible that this is an oversight where the documentation is simply not up to date/a bit misleading? I could not get accumulate to accept a three argument function either, and I'm surprised there's no error in your last example though I guess it would have to be paste that throws it. The fact that the text for .f is exactly the same for accumulate as for reduce makes me think that this just isn't functionality present in accumulate. Additionally, looking at the source seems to show (unless I misread) that reduce and reduce2 have their own implementation but accumulate relies on base::Reduce. Might be worth a GitHub issue.

Here's my best shot at producing the output you wanted. It basically involves calling reduce2 multiple times with the right subset of the input list and the secondary input vector to paste2, which doesn't feel very neat or tidy. This might just not be a particularly neat or tidy problem. Note the use of the {} to override the default %>% behaviour of placing the pipe LHS as the first argument, and the different indexing on .x and .y inside reduce2 (we want to keep .y one element shorter than .x).

paste2 <- function(x, y, sep = ".") paste(x, y, sep = sep)

library(purrr)
letters[1:4] %>%
  {map_chr(
    .x = 2:length(.),
    .f = function(index) reduce2(
      .x = .[1:index],
      .y = c("-", ".", "-")[1:(index - 1)],
      .f = paste2
    )
  )}
#> [1] "a-b"     "a-b.c"   "a-b.c-d"

Created on 2018-05-11 by the reprex package (v0.2.0).

Aquifer answered 11/5, 2018 at 18:15 Comment(0)
C
0

A few months after this post accumulate2 was introduced that gives the results OP was after:

library(purrr)

paste2 <- function(x, y, sep = ".") paste(x, y, sep = sep)
accumulate2(letters[1:4], c("-", ".", "-"), paste2)

#> [[1]]
#> [1] "a"
#> 
#> [[2]]
#> [1] "a-b"
#> 
#> [[3]]
#> [1] "a-b.c"
#> 
#> [[4]]
#> [1] "a-b.c-d"
Clump answered 13/2, 2022 at 6:53 Comment(0)
P
0

With this trick you can use unlimited arguments in accumulate and you did not even need accumulate2

library(tidyverse)

x <- letters[1:4]
y <- c('-', '.', '-')

accumulate(seq_along(x[-1]), .init = x[1], ~paste(.x, x[.y+1], sep = y[.y]))
#> [1] "a"       "a-b"     "a-b.c"   "a-b.c-d"

# OR

accumulate(seq_along(y), .init = x[1], ~paste(.x, x[.y+1], sep = y[.y]))
#> [1] "a"       "a-b"     "a-b.c"   "a-b.c-d"

Created on 2022-02-21 by the reprex package (v2.0.1)

Preprandial answered 21/2, 2022 at 9:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.