Loop over objects in global environment [duplicate] - r

This question already has answers here:
Get type of all variables
(6 answers)
Closed 4 years ago.
I'm pretty new to R and trying to write a loop or a concise code for a simple task: checking the class of all the current objects in my Global Environment in R.
class(mydata)
#[1] "data.frame"
class(mylist)
#[1] "list"
class(mymatrix)
#[1] "matrix"
...
The following code worked, but what if I have many objects and I don't want to type all the names.
dflist <- list(mydata, mylist, mymatrix)
lapply(dflist,class)
I tried the following methods, none of them worked.
#1
for (i in ls()){
class(i)
}
#2
for (i in ls()){
lapply(i,class)
}
any solutions? Thanks.

You could use mget which returns "a named list of objects". The function's first argument should be a character vector of object names, which is what ls() returns.
lapply(mget(ls()), class)
#$mydata
#[1] "data.frame"
#
#$mylist
#[1] "list"
#
#$mymatrix
#[1] "matrix"

Try eapply:
eapply(.GlobalEnv, class)

Using sapply:
sapply(ls()[sapply(ls(), function(x) any(class(get(x)) %in% c("data.frame", "matrix", "list")))], function(x) class(get(x)))

Related

Printing dataframe name within a for loop in R

I have a list of data frames. I want to perform a bunch of operations within a for loop but before that, I need to extract the string name of each dataset to use as variable/data frame name suffixes.
for(i in dflist) {
suffix<- deparse(substitute(i))
print(suffix)
}
However, my output shows as the following:
[1] "i"
[1] "i"
[1] "i"
I know that this is because of R's lazy evaluation framework. But how do I get around this limitation and get R to assign the names of data frames in dflist to the suffix variable ?
You are almost there. Try to understand what elements of a list are and how indexing works when you works with lists.
example data
dflist <- list(
name_df1 = data.frame(a = 1:3)
,name_df2 = data.frame(mee = c("A","B","C","D"))
)
understand list elements
What do we access with index i in a for loop over a list?
for(i in dflist){
print(class(i))
print(names(i))
}
[1] "data.frame"
[1] "a"
[1] "data.frame"
[1] "mee"
index extracts an object of class (here) data frame.
your case
for(i in dflist){
suffix <- names(i)
print(suffix)
}
[1] "a"
[1] "mee"

How to use purrr::map to base::assign?

How to get from meow to purr?
Let's say I have a list with 2 elements "a" and "b". I want to copy these elements into my Global environment. If I wanted to just add these elements to the search path, I'd use assign. However, I want to create a copy. And I'd like to use purrr::map to do this. How does it work?
mylist <- list(a=1:2, b=3:4)
#nope
map(mylist, assign, x=names(.), value=.)
#no
map(mylist, assign(x=names(.), value=.))
#no
map2(mylist, names(mylist), assign(x=.y, value=.x) )
#no
map2(mylist, names(mylist), assign, x=.y, value=.x )
Several responses to this :-)
Don't. My first visceral and emphatic response: don't do that. Very rarely do I find the use of get/assign justified, most commonly they are indications of inefficient (if not poor) data management. Having similar-structured things in a list means that you can efficiently operate on them (using map or lapply or similar).
Base R does this very efficiently with list2env.
ls()
# character(0)
list2env(list(a=1:2, b=3:4), envir = .GlobalEnv)
# <environment: R_GlobalEnv>
ls()
# [1] "a" "b"
If you must use purrr, then what you need is both the name and the value, so use purrr::imap:
ls()
# character(0)
imap(list(a=1:2, b=3:4), ~ assign(..2, ..1, envir = .GlobalEnv))
# $a
# [1] 1 2
# $b
# [1] 3 4
ls()
# [1] "a" "b"
The reason your assign calls failed was that it was assigning it to the then-current environment, which is neither global nor something you get to use after your call to map/map2.
Easier is list2env from base R applied directly on the named list to create the objects from the names in the global environment
list2env(mylist, .GlobalEnv)
Regarding the use of map, it returns only the value and not the names
A slightly related to this topic would be destructuring assignment. In R, this can be done with %<-% operator from zeallot
library(zeallot)
c(a, b) %<-% mylist

Name lists in R (not the elements)

I am trying to name a nested list. This would be one of the several lists in my nested list:
paths_list[i]
[[1]]
[[1]]$CLASS
[1] "Signal Transduction (Saccharomyces cerevisiae)"
[[1]]$GENES
[1] "YPR165W"
[[1]]$ORGANISM
[1] "Saccharomyces cerevisiae"
Basically what I want to do is to put an ID name for example R-SCE-198203 as the main name for the list (so above $CLASS it should appear the name R-SCE-198203). List paths_list[i] to have the name R-SCE-198203.
I want this:
paths_list[i]
[[1]]R-SCE-198203
[[1]]$CLASS
[1] "Signal Transduction (Saccharomyces cerevisiae)"
[[1]]$GENES
[1] "YPR165W"
[[1]]$ORGANISM
[1] "Saccharomyces cerevisiae"
I have searched and the closest I have found was with lapply but you ends up like this:
setNames(lapply(tabs, setNames, varB), varA)
#$varA1
#$varA1$varB1
#[1] "integer"
#
#$varA1$varB2
#[1] "integer"
# ...
I want to avoid the main ID to appear in every element of the list (do not want $varA1 being repeated all the time).
Is that possible?
Thanks in advance
I think your lapply approach is already what you want. The "true" names of the sub-elements do not have the $ signs. The output in the console when you print a full list object shows these signs to help you read the data, however, if you access the individual sub-element via [[]] their names do not have these signs. Maybe the following code example helps. Check the outputs.
a_list <- list("dummy")
names(a_list) <- "dummyname"
a_list <- list(a_list)
names(a_list) <- "name"
a_list
#$name
#$name$dummyname
#[1] "dummy"
names(a_list)
#[1] "name"
a_list[[1]]
#$dummyname
#[1] "dummy"
names(a_list[[1]])
#[1] "dummyname"

How to void type conversion in R's apply (bit64 example)

I am using the bit64 package in some R code. I have created a vector
of 64 bit integers and then tried to use sapply to iterate over these
integers in a vector. Here is an example:
v = c(as.integer64(1), as.integer64(2), as.integer64(3))
sapply(v, function(x){is.integer64(x)})
sapply(v, function(x){print(x)})
Both the is.integer64(x) and print(x) give the incorrect
(or at least) unexpected answers (FALSE and incorrect float values).
I can circumvent this by directly indexing the vector c but I have
two questions:
Why the type conversion? Is their some rule R uses in such a scenario?
Any way one can avoid this type conversion?
TIA.
Here is the code of lapply:
function (X, FUN, ...)
{
FUN <- match.fun(FUN)
if (!is.vector(X) || is.object(X))
X <- as.list(X)
.Internal(lapply(X, FUN))
}
Now check this:
!is.vector(v)
#TRUE
as.list(v)
#[[1]]
#[1] 4.940656e-324
#
#[[2]]
#[1] 9.881313e-324
#
#[[3]]
#[1] 1.482197e-323
From help("as.list"):
Attributes may be dropped unless the argument already is a list or
expression.
So, either you creaste a list from the beginning or you add the class attributes:
v_list <- lapply(as.list(v), function(x) {
class(x) <- "integer64"
x
})
sapply(v_list, function(x){is.integer64(x)})
#[1] TRUE TRUE TRUE
The package authours should consider writing a method for as.list. Might be worth a feature request ...

R get objects' names from the list of objects

I try to get an object's name from the list containing this object. I searched through similar questions and find some suggestions about using the deparse(substitute(object)) formula:
> my.list <- list(model.product, model.i, model.add)
> lapply(my.list, function(model) deparse(substitute(model)))
and the result is:
[[1]]
[1] "X[[1L]]"
[[2]]
[1] "X[[2L]]"
[[3]]
[1] "X[[3L]]"
whereas I want to obtain:
[1] "model.product", "model.i", "model.add"
Thank you in advance for being of some help!
You can write your own list() function so it behaves like data.frame(), i.e., uses the un-evaluated arg names as entry names:
List <- function(...) {
names <- as.list(substitute(list(...)))[-1L]
setNames(list(...), names)
}
my.list <- List(model.product, model.i, model.add)
Then you can just access the names via:
names(my.list)
names(my.list) #..............
Oh wait, you didn't actually create names did you? There is actually no "memory" for the list function. It returns a list with the values of its arguments but not from whence they came, unless you add names to the pairlist given as the argument.
You won't be able to extract the information that way once you've created my.list.
The underlying way R works is that expressions are not evaluated until they're needed; using deparse(substitute()) will only work before the expression has been evaluated. So:
deparse(substitute(list(model.product, model.i, model.add)))
should work, while yours doesn't.
To save stuffing around, you could employ mget to collect your free-floating variables into a list with the names included:
one <- two <- three <- 1
result <- mget(c("one","two","three"))
result
#$one
#[1] 1
#
#$two
#[1] 1
#
#$three
#[1] 1
Then you can follow #DWin's suggestion:
names(result)
#[1] "one" "two" "three"

Resources