I have a variable whose name and value are both determined dynamically. I want to append that variable to a list, so I need to express it in the form list(x). My difficulty is defining what x should be.
So, for example, if the value of the name is given by the variable a, and the value is b, I have both
a <- "name"
b <- 3
But then I get this result:
list(a = b)
$a
[1] 3
The value is correct but the name is not. I want the list to look behind the variable a to its current value, which is "name".
How do I do that, please?
Use lst from dplyr as the expression on the lhs of = is only evaluated literally and not the value stored int it.
library(dplyr)
lst(!! a:= b)
$name
[1] 3
Or with setNames/names<- from base R
setNames(list(b), a)
$name
[1] 3
`names<-`(list(b), a)
$name
[1] 3
Or create the list first and then rename
lst1 <- list(b)
names(lst1) <- a
We may use structure.
a <- 'name'; b <- 3
structure(as.list(b), names=a)
# $name
# [1] 3
It generalizes well for multiple pair-wise values.
a <- c('name1', 'name2'); b <- c(3, 4)
structure(as.list(b), names=a)
# $name1
# [1] 3
#
# $name2
# [1] 4
Related
I have a dataframe as such:
Number <- c(1,2,3)
Number2 <- c(10,12,14)
Letter <- c("A","B","C")
df <- data.frame(Number,Number2,Letter)
I would like to split the df into its respective three columns, each one becoming a vector with the respective column name. In essence, the output should look exactly like the original three input vectors in the above example.
I have tried the split function and also using for loop, but without success.
Any ideas? Thank you.
We may use unclass as data.frame is a list with additional attributes. By unclassing, it removes the data.frame attribute
unclass(df)
Or another option is asplit with MARGIN specified as 2
asplit(df, 2)
NOTE: Both of them return a named list. If we intend to create new objects in the global env, use list2env (not recommended though)
We can use c oras.list
> c(df)
$Number
[1] 1 2 3
$Number2
[1] 10 12 14
$Letter
[1] "A" "B" "C"
> as.list(df)
$Number
[1] 1 2 3
$Number2
[1] 10 12 14
$Letter
[1] "A" "B" "C"
Assuming you are trying to create these as vectors if the global environment, use list2env:
df <- data.frame(Number = c(1, 2, 3),
Number2 = c(10, 12, 14),
Letter = c("A", "B", "C"))
list2env(df, .GlobalEnv)
## <environment: R_GlobalEnv>
ls()
## [1] "df" "Letter" "Number" "Number2"
list2env is clearly the easiest way, but if you want to do it with a for loop it can also be achieved.
The "tricky" part is to make a new vector based on the column names inside the for loop. If you just write
names(df[i]) <- input
a vector will not be created.
A workaround is to use paste to create a string with the new vector name and what should be in it, then use "eval(parse(text=)" to evaluate this expression.
Maybe not the most elegant solution, but seems to work.
for (i in colnames(df)){
vector_name <- names(df[i])
expression_to_be_evaluated <- paste(vector_name, "<- df[[i]]")
eval(parse(text=expression_to_be_evaluated))
}
> Letter
[1] A B C
Levels: A B C
> Number
[1] 1 2 3
> Number2
[1] 10 12 14
I want create a list of objects that includes a dataframe df, where df is added as the first object to an existing list. In the example, list_1 is the existing list, and I want to create list of length 3 where df is the first object. Here's what I tried: For list_2, I used list() and got a list length=2. In list_4, append() just added the objects in list_1 to df. In the final attempt, I created a list of length=3, but with df at the end. It seems like there's something really obvious that I'm missing?
df <- tibble(x=c("a","b","c"),
y=c("d","e","f"))
list_1 <- list("one" = 1,
"chr" = "string")
list_2 <- list(df, list_1)
list_4 <- append(df, list_1)
list_1$df <- df
You could use the c function which also handles list object type.
The default method combines its arguments to form a vector. All arguments are coerced to a common type which is the type of the returned value
Putting the dataframe in a list protects it from being split into its columns :
c(list_1,df = list(df))
$one
[1] 1
$chr
[1] "string"
$df
# A tibble: 3 x 2
x y
<chr> <chr>
1 a d
2 b e
3 c f
c(df = list(df),list_1)
$df
# A tibble: 3 x 2
x y
<chr> <chr>
1 a d
2 b e
3 c f
$one
[1] 1
$chr
[1] "string"
Expand.grid is simple to use, but it requires entering the specific vectors:
a = 1:5
b = 2:5
c = 3:5
df = expand.grid(a,b,c)
But a b and c are arbitrary and are not real names, how can I use it for unknown variables or a list. I tried:
rm(list = ls())
a = 1:5
b = 2:5
c = 3:5
l = ls()
[1] "a" "b" "c"
get(l[1])
[1] 1 2 3 4 5
df = expand.grid(get(l))
L is the list of variables and get gives pulls the variables by name so I expected the two to give the same result but it gives the result of only a.
How can I get the desired result for expand.grid without entering static values?
We can use mget instead of get (as get returns only a single object) to return multiple object values
expand.grid(mget(l))
I want to create a named list where each name has multiple values. I can only find how to do this if for each name there is one value. My solution that I am using now is
df <- data.frame(col1=c('a','a','b','b'), col2=c(1,2,3,4))
l <- list()
for(letter in unique(df$col1)){
l[[letter]] <- df[df$col1==letter,]$col2
}
> l
$a
[1] 1 2
$b
[1] 3 4
but what is a better way to do this?
We can use split to return a named list of vectors
split(df$col2, df$col1)
I have a character vector that looks like this
vector <- c('a','b','c','d','e')
I have an object in a for-loop that takes input as:
out[a,] <- c(a,b,c,d,e)
Where a-e are variables with values (for instance, a=0.7). I would like to feed the out object some transfomred version of ther vector object. I've tried
paste(noquote(vector),collapse=',')
However, this just returns
"a,b,c,d,e"
Which is still not useful.
Reverse the order of the function calls:
noquote(paste(vector, collapse = ','))
This will print [1] a,b,c,d,e. If you don't like the [1] use
cat(paste(vector, collapse = ','))
which prints
a,b,c,d,e
You can use mget to put objects into a named list:
# data
a <- 1; b <- 2; c <- 3; d <- 4; e <- 5
mget(letters[1:5])
$a
[1] 1
$b
[1] 2
$c
[1] 3
$d
[1] 4
$e
[1] 5
or wrap it mget in unlist to get a named vector:
unlist(mget(letters[1:5]))
a b c d e
1 2 3 4 5
This is very basic question and ate my head almost with a tiny mistake every time. I simplified and created a function in R language.
Here you go buddy!
numbers <- list(2,5,8,9,14,20) #List containing even odd numbers
en<-list() #Initiating even numbers’ list
on<-list() #Initiating odd numbers’ list
#Function creation
separate <- function(x){
for (i in x)
{
ifelse((i%%2)==0, en <- paste(append(en,i, length(en)+1), collapse = ","),
on <- paste(append(on,i, length(on)+1), collapse = ","))
}
message("Even numbers are : ", en)
message("Odd numbers are : ", on)
}
#Passing the function with argument
separate(numbers)
Result!
Even numbers are : 2,8,14,20
Odd numbers are : 5,9