Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Introduction
Did you know that the magrittr
pipe, %>%
, can be used for more than just data.frame
s and tibble
s? In this blog post, we look at how we can create get and set functions for list elements.
Getting List Elements
First, let’s create a simple list.
z1 <- list(a = pi, b = 2.718, c = 0.57721) z1 # $a # [1] 3.141593 # # $b # [1] 2.718 # # $c # [1] 0.57721
Let’s say we want to access an element of this list, typically we would use the [[
function to do so.
z1[[2]] # [1] 2.718
But let’s say we need to access this list as part of a chain using magrittr
’s pipe operator, %>%
. How can we do that? Well we can pipe our list into a .
which acts as a placeholder for the list, on which we can perform our subset.
library(magrittr) z1 %>% .[[2]] # [1] 2.718
Another solution is to call [[
using its syntactic form [[()
using backticks (or quotes, see ?Quotes
).
z1 %>% `[[`(2) # [1] 2.718
Admittedly, these two solutions don’t look very nice. So what we can do instead is assign the [[
function to an object which will, in effect, be a callable wrapper function.
get <- .Primitive("[[") # Equivalent to get <- `[[` get(z1, 2) # [1] 2.718
Primitives are functions that are internally implemented by R and so .Primitive("[[")
tells R to dispatch to the underlying C code, which will be able to correctly identify which [[
method to use on the list class (see ?.Primitive
for more details).
Since our list is now the first argument of get()
, we have a much “cleaner” looking way of accessing elements of a list with the magrittr
pipe operator than [[
. And so, let’s access the second element of our list using get()
and the magrittr
pipe.
z1 %>% get(2) # [1] 2.718
We can also access the list using its names, too.
z1 %>% get("b") # [1] 2.718
It even works with recursive indexing!
z2 <- list(a = list(b = 9, c = "hello"), d = 1:5) z2 # $a # $a$b # [1] 9 # # $a$c # [1] "hello" # # # $d # [1] 1 2 3 4 5 z2 %>% get(c("a", "c")) # equivalent to z %>% get(c(1, 2)) # [1] "hello"
Note, you may want to choose a better name than get
to avoid clashes with the base::get()
function.
Setting List Elements
Similarly we can create a set()
function to assign values to elements of our list using .Primitive("[[<-")
. Let’s add a fourth element to our list.
set <- .Primitive("[[<-") z1 <- z1 %>% set("d", 4.6692) z1 # $a # [1] 3.141593 # # $b # [1] 2.718 # # $c # [1] 0.57721 # # $d # [1] 4.6692
And now just as set()
giveth, set()
taketh away.
z1 <- z1 %>% set("d", NULL) z1 # $a # [1] 3.141593 # # $b # [1] 2.718 # # $c # [1] 0.57721
Of course as this is a list, we can set any kind of data.
z1 %>% set("data", data.frame(a = c(1, 2, 2, 4), b = c(2, 3, 7, 4))) # $a # [1] 3.141593 # # $b # [1] 2.718 # # $c # [1] 0.57721 # # $data # a b # 1 1 2 # 2 2 3 # 3 2 7 # 4 4 4
Or even overwrite elements.
z1 %>% set("b", 4.6692) # $a # [1] 3.141593 # # $b # [1] 4.6692 # # $c # [1] 0.57721
Conclusion
This was just a short blog post to highlight the power of magrittr
in combination with R primitives. We also saw how to rewrite and manipulate syntactic forms of internal R functions. What other interesting use cases have you found for the magrittr
pipe?
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.