This question already has answers here:
Can lists be created that name themselves based on input object names?
(4 answers)
Closed 4 years ago.
I've looked extensively for a solution for this very simple task and though I have a solution, it seems like there must be a better way. The task is to create a list from a set of variables, using the variable names as names for each element in the list, e.g.:
a <- 2
b <- 'foo'
c <- 1:4
My current solution:
named.list <- function(...) {
l <- list(...)
names(l) <- sapply(substitute(list(...)), deparse)[-1]
l
}
named.list(a,b,c)
Produces:
$a
[1] 2
$b
[1] "foo"
$c
[1] 1 2 3 4
A couple of ways I can think of include mget (make assumptions about the environment your objects are located in):
mget( c("a","b","c") )
$a
[1] 2
$b
[1] "foo"
$c
[1] 1 2 3 4
Or as an edit to your function, you could use, match.call like this:
named.list <- function(...) {
l <- list(...)
names(l) <- as.character( match.call()[-1] )
l
}
named.list( a,b,c)
$a
[1] 2
$b
[1] "foo"
$c
[1] 1 2 3 4
Or you can do it in one go using setNames like this:
named.list <- function(...) {
l <- setNames( list(...) , as.character( match.call()[-1]) )
l
}
named.list( a,b,c)
$a
[1] 2
$b
[1] "foo"
$c
[1] 1 2 3 4
If you already using tidyverse packages, then you might be interested in using the tibble::lst function which does this
tibble::lst(a, b, c)
# $a
# [1] 2
#
# $b
# [1] "foo"
#
# $c
# [1] 1 2 3 4
Related
I am pretty new in R and so what I am trying to do is that I have been given a vector of positive integers like
index <- 1:3
and I want to use this vector to find all the possible combinations of numbers without repetition which I achieve like this
for (i in 1:length(index)) {
combn(index,i)
j = 1
while (j <= nrow(t(combn(index,i)))) {
print(t(combn(index,i))[j,])
j = j + 1
append(comb, j)
}
}
This gives me output as
[1] 1
[1] 2
[1] 3
[1] 1 2
[1] 1 3
[1] 2 3
[1] 1 2 3
But when I create a list comb <- list() and try to append each output as below:
for (i in 1:length(index)) {
combn(index,i)
j = 1
while (j <= nrow(t(combn(index,i)))) {
append(comb, t(combn(index,i))[j,])
j = j + 1
}
}
The problem is it is giving my empty list when I call
comb
list()
I wish to create a list with those elements and use them to retrieve those index rows from a data frame. Do you have any idea how I can achieve this? Any help is welcome. Thanks!
We can use unlist + lapply like below
unlist(
lapply(
seq_along(index),
combn,
x = index,
simplify = FALSE
),
recursive = FALSE
)
which gives
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 1 2
[[5]]
[1] 1 3
[[6]]
[1] 2 3
[[7]]
[1] 1 2 3
This seems to give what you want
index <- 1:3
comb <- list()
for (i in 1:length(index)) {
combn(index,i)
j = 1
while (j <= nrow(t(combn(index,i)))) {
comb <- c(comb, list(t(combn(index,i))[j,]))
j = j + 1
}
}
comb
Output
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 1 2
[[5]]
[1] 1 3
[[6]]
[1] 2 3
[[7]]
[1] 1 2 3
Note that you have to assign your appended list back. Also if you append a list with vector each of the vector element will be a separate element in the new list. You have to wrap that vector in a list() function to append it as one.
I have the following data table (in the example I just take 3 rows):
data <- data.table(var=c("a","b","c"), value=c(-1,2,1))
I would like to extract each variable as value without subsetting each time that I need one of them.
I would like to get the follwing output:
a <- -1
b <- 2
c <- 1
An option is split to return a key/value pair. It is better not to create objects in the global environment
lst1 <- split(data$value, data$var)
lst1
#$a
#[1] -1
#$b
#[1] 2
#$c
#[1] 1
But, if we need it,
list2env(lst1, .GlobalEnv)
a
#[1] -1
b
#[1] 2
c
#[1] 1
Or another option is deframe and then use list2env
library(tibble)
list2env(as.list(deframe(data)), .GlobalEnv)
Though creating objects in the global environment is not recommended, we can try eval(parse(...)) methodology to address your question,
eval(parse(text = do.call(paste, c(data, sep = '<-'))))
a
#[1] -1
b
#[1] 2
c
#[1] 1
With purrr:
res<-purrr::map2(data$var, data$value,
function(x,y)
x <- y
)
names(res) <- data$var
The above sets the names after getting the result.
res
$a
[1] -1
$b
[1] 2
$c
[1] 1
With base's mapply, we could use:
as.list(mapply(function(x,y) assign(x,y,new.env()),
data$var,data$value))
$a
[1] -1
$b
[1] 2
$c
[1] 1
Or:
mapply(function(x,y) append(list(),y),
data$var,data$value)
$a
[1] -1
$b
[1] 2
$c
[1] 1
I have two list m.list and the other r.list. The m.list has NA values. For those that have NA values, I would like to replace it with elements from r.list. The problem is when I use replace function in R it is taking the index of the r.list and returns a incorrect value. Below is reproducible examples. IS there a way to replace value of one list based on the element name from another list?
m.list <- list(a= 1,b=NA,c=3,d=NA)
r.list <- list(a= 4,d=8,c=9)
mr.list <- replace(m.list, which(is.na(m.list)), r.list[which(is.na(m.list))])
Here is the output that I get b should be NA and d should be 8:
> mr.list
$a
[1] 1
$b
[1] 8
$c
[1] 3
$d
NULL
here is the desired output:
$a
[1] 1
$b
[1] NA
$c
[1] 3
$d
[1] 8
Here is an option with modifyList
modifyList(m.list, r.list[intersect(names(r.list), names(which(is.na(m.list))))])
#$a
#[1] 1
#$b
#[1] NA
#$c
#[1] 3
#$d
#[1] 8
If we split the code, the idea is to find the names in 'm.list' where the value is missing and that is also found in 'r.list' (intersect), then with modifyList replace the values in 'm.list' with the subset of 'r.list'
nm1 <- intersect(names(r.list), names(which(is.na(m.list))))
modifyList(m.list, r.list[nm1])
You can use replace but you need to match the names of the lists and make sure that you also include the is.na(m.list) in the replacement argument to ensure equal lengths
l1 <- replace(m.list, is.na(m.list),
r.list[match(names(m.list),
names(r.list))][is.na(m.list)])
which gives,
$a
[1] 1
$b
NULL
$c
[1] 3
$d
[1] 8
NOTE: To replace NULL with NA, simply,
l1[lengths(l1) == 0] <- NA
We can first find the position of the value that is to be replaced. It must exist in r.list
a=names(m.list)%in%names(r.list)&is.na(m.list)
replace(m.list, a, r.list[names(which(a))])
$a
[1] 1
$b
[1] NA
$c
[1] 3
$d
[1] 8
I have list l of the form say :
R> l
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 4
Now, I want to merge to member lists of this list. For instance, when I say I want to merge l[[1]] and l[[2]], I want the result to be :
R> l
[[1]]
[1] 1 2
[[2]]
[1] 3
[[3]]
[1] 4
While merging two list, I don't need dupilcate elements in the result. Hence, I am using union over two member lists.
R> union(l[[1]], l,[[2]])
[1] 1 2
How can I do this merge operation? Can I do this using some predefined function?
Thanks
You can write you own merge as follows:
l <- as.list(1:4)
mymerge <- function(mylist, element1, element2){
mylist[[element1]] <- union(mylist[[element1]], mylist[[element2]])
mylist[[element2]] <- NULL
return(mylist)
}
l <- mymerge(l,1,2)
Result:
> l
[[1]]
[1] 1 2
[[2]]
[1] 3
[[3]]
[1] 4
Comment: As akrun pointed out, you can also use c instead of union
I have the following list in R and I want to replace all NULL in the list with zero. Is there a better way of doing this rather than iterating through the list?
$`2014-06-15`
NULL
$`2014-06-16`
[1] 7
$`2014-06-17`
[1] 17
$`2014-06-18`
[1] 24
$`2014-06-19`
[1] 8
$`2014-06-20`
[1] 11
$`2014-06-21`
NULL
$`2014-06-22`
[1] 1
$`2014-06-23`
[1] 20
$`2014-06-24`
[1] 21
In reference to your solution, this way is easier and faster than replacing with a for loop and if statement. Here's a short example.
> ( temp <- list(A = NULL, B = 1:5) )
# $A
# NULL
#
# $B
# [1] 1 2 3 4 5
> temp[sapply(temp, is.null)] <- 0
> temp
# $A
# [1] 0
#
# $B
# [1] 1 2 3 4 5
Nevermind solved it.
temp is my list of dates above
allDates <- names(temp)
for (i in allDates) {
if (is.null(temp[[i]]))
temp[[i]] <- 0
}