Create an ellipsis (...) from list - r

Is it possible to create a ellipsis (...) from a list? The idea is to be able to do something like:
mylist <- list(a=1,b=2,c=3)
myellipsis <- create_ellipsis(mylist)
print(switch('a', myellipsis)) # output 1

You want do.call, which can pass the content of a list to a functions ... argument:
do.call(function(...) print(switch('a', ...)), mylist)

Related

Loss of attributes with lapply (R)

If I have a list with some attribute, and I apply a function to all elements of that list, the attribute gets removed.
# Define list and attribute
my_list <- list(1,2,3)
attr(my_list, "my_attribute") <- "foo"
# Function that I will apply over list elements
add_1 <- function (x) {
return(x + 1)
}
my_list <- lapply(my_list, add_1)
# Attribute is lost
attributes(my_list)
#> NULL
How can I keep the list attributes after lapply?
Well I guess I could just store the attributes before the lapply call
# Define list and attribute
...
# Function that I will apply over list elements
...
stored_attributes <- attributes(my_list)
my_list <- lapply(my_list, add_1)
attributes(my_list) <- stored_attributes
... still, I don't really understand this behaviour
A way to retain the attributes is with [] -
my_list[] <- lapply(my_list, add_1)
attributes(my_list)
#$my_attribute
#[1] "foo"

Create an S4 class object in R with some of the arguments passed using the ellipsis

How could I use some of the arguments passed to a function using the ellipsis to create a new object of an S4 class, while naming the arguments?
Example:
foo <- function(a, ...){
cur_args <- lapply(match.call(expand.dots=TRUE)[-1], deparse)
args_to_keep <- names(cur_args) %in% slotNames("myClass1")
newClassObj <- new("myClass1", what can go here??? )
}
Is there any way to use do.call and comply with the types of the slots of the class / retain the type as it was passed to foo?
newClassObj <- do.call( "new", as.list( c("Class"="myClass1", cur_args[args_to_keep] )) )
You have the right idea,
you just have to create the list of arguments passed to new correctly:
setClass("A", slots=c(x="numeric"))
foo <- function(...) {
dots <- list(...)
valid_slots <- dots[intersect(names(dots), slotNames("A"))]
do.call(new, c(list(Class="A"), valid_slots))
}
> foo(x=1, y=2)
An object of class "A"
Slot "x":
[1] 1
c can be used to append lists to each other,
so you just need to wrap Class="A" in a list.

Update first value in each list element in R

I would like to replace the first value in each list element with the second value from the same element.
For example I would like a function to transform lst into lst2
lst<-list(c(0:4),c(5:9))
lst
lst2<-list(c(1, c(1:4)),c(6,c(6:9)))
lst2
I know that I can do
lst[[1]][1]=lst[[1]][2]
lst[[2]][1]=lst[[2]][2]
But I would like a function to iterate over all list elements. I have tried various things (all unsuccessful) with lapply such as:
lapply(list, function(x) x[1]=x[2])
We can use lapply to loop over the list and we need to return the x if we are using anonymous function call.
lstN <- lapply(lst, function(x) {x[1] <- x[2]
x})
identical(lst2, lstN)
#[1] TRUE

Is there a way to view a list

When I have data.frame objects, I can simply do View(df), and then I get to see the data.frame in a nice table (even if I can't see all of the rows, I still have an idea of what variables my data contains).
But when I have a list object, the same command does not work. And when the list is large, I have no idea what the list looks like.
I've tried head(mylist) but my console simply cannot display all of the information at once. What's an efficient way to look at a large list in R?
Here's a few ways to look at a list:
Look at one element of a list:
myList[[1]]
Look at the head of one element of a list:
head(myList[[1]])
See the elements that are in a list neatly:
summary(myList)
See the structure of a list (more in depth):
str(myList)
Alternatively, as suggested above you could make a custom print method as such:
printList <- function(list) {
for (item in 1:length(list)) {
print(head(list[[item]]))
}
}
The above will print out the head of each item in the list.
I use str to see the structure of any object, especially complex list's
Rstudio shows you the structure by clicking at the blue arrow in the data-window:
You can also use a package called listviewer
library(listviewer)
jsonedit( myList )
If you have a really large list, you can look at part of it using
str(myList, max.level=1)
(If you don't feel like typing out the second argument, it can be written as max=1 since there are no other arguments that start with max.)
I do this often enough that I have an alias in my .Rprofile for it:
str1 <- function(x, ...) str(x, max.level=1, ...)
And a couple others that limit the printed output (see example(str) for an example of using list.len):
strl <- function(x, len=10L, ...) str(x, list.len=len, ...) # lowercase L in the func name
str1l <- function(x, len=10L, ...) str(x, max.level=1, list.len=len, ...)
you can check the "head" of your dataframes using lapply family:
lapply(yourList, head)
which will return the "heads" of you list.
For example:
df1 <- data.frame(x = runif(3), y = runif(3))
df2 <- data.frame(x = runif(3), y = runif(3))
dfs <- list(df1, df2)
lapply(dfs, head)
Returns:
> lapply(dfs, head)
[[1]]
x y
1 0.3149013 0.8418625
2 0.8807581 0.5048528
3 0.2490966 0.2373453
[[2]]
x y
1 0.4132597 0.5762428
2 0.0303704 0.3399696
3 0.9425158 0.5465939
Instead of "head" you can use any function related to the data.frames, i.e. names, nrow...
Seeing as you explicitly specify that you want to use View() with a list, this is probably what you are looking for:
View(myList[[x]])
Where x is the number of the list element that you wish to view.
For example:
View(myList[[1]])
will show you the first element of the list in the standard View() format that you will be used to in RStudio.
If you know the name of the list item you wish to view, you can do this:
View(myList[["itemOne"]])
There are several other ways, but these will probably serve you best.
This is a simple edit of giraffehere's excellent answer.
For some lists it is convenient to only print the head of a subset of the nested objects, to print the name of the given slot above the output of head().
Arguments:
#'#param list a list object name
#'#param n an integer - the the objects within the list that you wish to print
#'#param hn an integer - the number of rows you wish head to print
USAGE: printList(mylist, n = 5, hn = 3)
printList <- function(list, n = length(list), hn = 6) {
for (item in 1:n) {
cat("\n", names(list[item]), ":\n")
print(head(list[[item]], hn))
}
}
For numeric lists, output may be more readable if the number of digits is limited to 3, eg:
printList <- function(list, n = length(list), hn = 6) {
for (item in 1:n) {
cat("\n", names(list[item]), ":\n")
print(head(list[[item]], hn), digits = 3)
}
}
I had a similar problem and managed to solve it using as_tibble() on my list (dplyr or tibble packages), then just use View() as usual.
In recent versions of RStudio, you can just use View() (or alternatively click on the little blue arrow beside the object in the Global Environment pane).
For example, if we create a list with:
test_list <- list(
iris,
mtcars
)
Then either of the above methods will show you:
I like using as.matrix() on the list and then can use the standard View() command.

Getting names from ... (dots)

In improving an rbind method, I'd like to extract the names of the objects passed to it so that I might generate unique IDs from those.
I've tried all.names(match.call()) but that just gives me:
[1] "rbind" "deparse.level" "..1" "..2"
Generic example:
rbind.test <- function(...) {
dots <- list(...)
all.names(match.call())
}
t1 <- t2 <- ""
class(t1) <- class(t2) <- "test"
> rbind(t1,t2)
[1] "rbind" "deparse.level" "..1" "..2"
Whereas I'd like to be able to retrieve c("t1","t2").
I'm aware that in general one cannot retrieve the names of objects passed to functions, but it seems like with ... it might be possible, as substitute(...) returns t1 in the above example.
I picked this one up from Bill Dunlap on the R Help List Serve:
rbind.test <- function(...) {
sapply(substitute(...()), as.character)
}
I think this gives you what you want.
Using the guidance here How to use R's ellipsis feature when writing your own function?
eg substitute(list(...))
and combining with with as.character
rbind.test <- function(...) {
.x <- as.list(substitute(list(...)))[-1]
as.character(.x)
}
you can also use
rbind.test <- function(...){as.character(match.call(expand.dots = F)$...)}

Resources