1

I would like to pipe (chain) magrittr object into loop. How can I do this?
I will use dummy operations/data as an example:

library(data.table)
library(magrittr)

# Dummy data modification
d <- mtcars %>%
    setDT() %>%
    .[, cylSQ := sqrt(cyl)] %>%
    .[, carb3 := carb^3]
# Dummy loop
res <- list()
for(i in unique(d$gear)) {
    res[[i]] <- d[gear == i] %>%
        .[, lm(cylSQ ~ mpg + carb3 * wt)] %>%
        .$fitted.values
}

Is it possible not to create object d and to pipe it directly to loop? For example:

for(i in unique(.$gear)) {
    res[[i]] <- .[gear == i] %>%
    ...
}

Edit: I don't want to replace loop with data.table or dplyr, just curious about piping.

pogibas
  • 27,303
  • 19
  • 84
  • 117
  • 1
    I might be wrong, is not the reason there is `purrr` package? – zx8754 Aug 26 '16 at 13:06
  • @zx8754 I haven't heard about it before, don't know it is what I am looking for, but still it seems very good and worth looking at. Thanks for good suggestion! – pogibas Aug 26 '16 at 13:09
  • 1
    `mtcars %>% setDT` goes against the dplyr grammar/philosophy of not modifying input, fyi. – Frank Aug 26 '16 at 14:12
  • @Frank doesn't `%>%` do copy? I tried `setDT(mtcars)` and it throws error, as expected. – jangorecki Aug 26 '16 at 15:14
  • @jangorecki Yeah, that's what I thought would happen but somehow the pipe overrides the lock, so `mtcars %>% setDT` actually alters `mtcars`. – Frank Aug 26 '16 at 15:15
  • 5
    [Don't pipe in a loop](http://stackoverflow.com/a/38882226/817778) – eddi Aug 26 '16 at 16:28

3 Answers3

3

Don't you mind using dplyr instead of data.table here? If not, try this:

library(dplyr)
d <- mtcars %>% 
    mutate(cylSQ = sqrt(cyl), carb3 = carb^3) %>% 
    group_by(gear) %>% 
    do(fitted.values = lm(cylSQ ~ mpg + carb3 * wt, data = .)[["fitted.values"]])
Iaroslav Domin
  • 2,698
  • 10
  • 19
2

This is a bit of sketchy work around, but you can use the exposition operator in the magrittr package %$%.

I.e.:

mtcars %>% 
  filter(hp > 1) %$%
  for(i in 1:ncol(.)) {
    print(.[1,i])
  }

[1] 21
[1] 6
[1] 160
[1] 110
[1] 3.9
[1] 2.62
[1] 16.46
[1] 0
[1] 1
[1] 4
[1] 4
Chris C
  • 1,625
  • 1
  • 19
  • 22
1

I'm not magrittr practitioner so it could probably be improved, but at least works, and should be efficient.

as.data.table(mtcars
              )[, cylSQ := sqrt(cyl)
                ][, carb3 := carb^3
                  ][, lm(cylSQ ~ mpg + carb3 * wt)$fitted.values, by=gear
                    ] %>% 
    split(by = "gear", keep.by = FALSE) %>% 
    lapply(unlist) %>% 
    lapply(unname) -> res

Due to new split.data.table it requires data.table in 1.9.7, see installation wiki for details how to install on various platforms.

jangorecki
  • 16,384
  • 4
  • 79
  • 160