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
Related
I have a list of a list with high complicated data. I would like to compare the values of each list and extract the smallest values. For simplicity, I provide a similar example.
s <- c(1,2,3)
ss <- c(4,5,6)
S <- list(s,ss)
h <- c(4,8,7)
hh <- c(0,3,4)
H <- list(h,hh)
HH <- list(S,H)
I would like to compare the element of each list with the element of the corresponding list and extract the smallest values. For example, the following are the values of HH list.
> HH
[[1]]
[[1]][[1]]
[1] 1 2 3
[[1]][[2]]
[1] 4 5 6
[[2]]
[[2]][[1]]
[1] 4 8 7
[[2]][[2]]
[1] 0 3 4
Now, I would like to compare
[[1]]
[[1]][[1]]
[1] 1 2 3
with
[[2]]
[[2]][[1]]
[1] 4 8 7
For example, 1 < 4, so I will select 1. For the second element, 2 < 8, so I will select 2. So, I would like to compare the elements of [[1]][[1]] with the elements of [[2]][[1]], and [[1]][[2]] with [[2]][[2]].
Then, I would like to print the name of the list. For example,
I expected to have similar to the following:
1 < 4, the first element of the first model is selected.
We could use a general solution (i.e. if there are many list elements) transpose from purrr to rearrange the list elements, and then use max.col to get the index
library(magrittr)
library(purrr)
HH %>%
transpose %>%
map(~ .x %>%
invoke(cbind, .) %>%
multiply_by(-1) %>%
max.col )
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 2 2 2
Or using base R
do.call(Map, c(f = function(...) max.col(-1 * cbind(...)), HH))
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 2 2 2
Maybe you can try this -
Map(function(x, y) as.integer(x > y) + 1, HH[[1]], HH[[2]])
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 2 2 2
This gives the position of the element selected.
In R, I am calling unlist on a list to convert to a vector. However, some of my list elements are empty, and hence returns integer(0). The unlist() function by default drops this. How can I return a vector that has NA where the list is empty? I have created a reproducible example:
> ex.list <- list()
> ex.list[[1]] <- integer(0)
> ex.list[[2]] <- c(1,2,3)
> ex.list
[[1]]
integer(0)
[[2]]
[1] 1 2 3
> unlist(ex.list)
[1] 1 2 3
Thanks.
A way of doing it is to use function is.na<-.
is.na(ex.list) <- lengths(ex.list) == 0
ex.list
#[[1]]
#[1] NA
#
#[[2]]
#[1] 1 2 3
Then you will have a NA where the list had a length of 0.
unlist(ex.list)
#[1] NA 1 2 3
We can do an assignment based on the length of the list element i.e. if it is equal to 0, assign as NA
ex.list[lengths(ex.list)==0] <- NA
ex.list
#[[1]]
#[1] NA
#[[2]]
#[1] 1 2 3
You could also try the one-liner
unlist(lapply(ex.list, function (x) ifelse(length (x) > 0, x, NA)))
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
Assume that this is my list
a <- list(c(1,2,4))
a[[2]] <- c(2,10,3,2,7)
a[[3]] <- c(2, 2, 14, 5)
How do I subset this list to exclude all the 2's. How do I obtain the following:
[[1]]
[1] 1 4
[[2]]
[1] 10 3 7
[[3]]
[1] 14 5
My current solution:
for(j in seq(1, length(a))){
a[[j]] <- a[[j]][a[[j]] != 2]
}
However, this approach feels a bit unnatural. How would I do the same thing with a function from the apply family?
Thanks!
lapply(a, function(x) x[x != 2])
#[[1]]
#[1] 1 4
#
#[[2]]
#[1] 10 3 7
#
#[[3]]
#[1] 14 5
Using lapply you can apply the subset to each vector in the list. The subset used is, x[x != 2].
Or use setdiff by looping over the list with lapply
lapply(a, setdiff, 2)
#[[1]]
#[1] 1 4
#[[2]]
#[1] 10 3 7
#[[3]]
#[1] 14 5
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