Google search doesn't return much on this. How do you unpack arguments in R?
For instance if I try to use switch in R like
switch("AA",c("AA"=5,"BB"=6))
I will get back c("AA"=5,"BB"=6) when in reality, I want 5.
Essentially, I want to be able to do switch("AA","AA"=5,"BB"=6) with a vector mapping.
This is a bit of a workaround, but try:
do.call("switch", append(list("AA"), list("AA"=5, "BB"=6)))
The do.call() allows you to pass a list of arguments into switch().
This is how switch was intended to be used. The first argument gets evaluated and match to the first elements of the succeeding pairlists:
aa <- "AA"
switch(aa,"AA"=5,"BB"=6)
#[1] 5
switch("BB","AA"=5,"BB"=6)
#[1] 6
At least that is the strategy for 'character' arguments. The process for numeric arguments is different. One needs to read the Details section of ?switch carefully.
Your example is rather short, mayby you could obtain demanded functionality this way :
my.vector = c("AA"=5,"BB"=6)
my.vector[names(my.vector ) == "AA"]
AA
5
?
> c("AA"=5,"BB"=6)["AA"]
AA
5
> c("AA"=5,"BB"=6)["BB"]
BB
6
Related
I am using R to parse a list of strings in the form:
original_string <- "variable_name=variable_value"
First, I extract the variable name and value from the original string and convert the value to numeric class.
parameter_value <- as.numeric("variable_value")
parameter_name <- "variable_name"
Then, I would like to assign the value to a variable with the same name as the parameter_name string.
variable_name <- parameter_value
What is/are the function(s) for doing this?
assign is what you are looking for.
assign("x", 5)
x
[1] 5
but buyer beware.
See R FAQ 7.21
http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f
You can use do.call:
do.call("<-",list(parameter_name, parameter_value))
There is another simple solution found there:
http://www.r-bloggers.com/converting-a-string-to-a-variable-name-on-the-fly-and-vice-versa-in-r/
To convert a string to a variable:
x <- 42
eval(parse(text = "x"))
[1] 42
And the opposite:
x <- 42
deparse(substitute(x))
[1] "x"
The function you are looking for is get():
assign ("abc",5)
get("abc")
Confirming that the memory address is identical:
getabc <- get("abc")
pryr::address(abc) == pryr::address(getabc)
# [1] TRUE
Reference: R FAQ 7.21 How can I turn a string into a variable?
Use x=as.name("string"). You can use then use x to refer to the variable with name string.
I don't know, if it answers your question correctly.
strsplit to parse your input and, as Greg mentioned, assign to assign the variables.
original_string <- c("x=123", "y=456")
pairs <- strsplit(original_string, "=")
lapply(pairs, function(x) assign(x[1], as.numeric(x[2]), envir = globalenv()))
ls()
assign is good, but I have not found a function for referring back to the variable you've created in an automated script. (as.name seems to work the opposite way). More experienced coders will doubtless have a better solution, but this solution works and is slightly humorous perhaps, in that it gets R to write code for itself to execute.
Say I have just assigned value 5 to x (var.name <- "x"; assign(var.name, 5)) and I want to change the value to 6. If I am writing a script and don't know in advance what the variable name (var.name) will be (which seems to be the point of the assign function), I can't simply put x <- 6 because var.name might have been "y". So I do:
var.name <- "x"
#some other code...
assign(var.name, 5)
#some more code...
#write a script file (1 line in this case) that works with whatever variable name
write(paste0(var.name, " <- 6"), "tmp.R")
#source that script file
source("tmp.R")
#remove the script file for tidiness
file.remove("tmp.R")
x will be changed to 6, and if the variable name was anything other than "x", that variable will similarly have been changed to 6.
I was working with this a few days ago, and noticed that sometimes you will need to use the get() function to print the results of your variable.
ie :
varnames = c('jan', 'feb', 'march')
file_names = list_files('path to multiple csv files saved on drive')
assign(varnames[1], read.csv(file_names[1]) # This will assign the variable
From there, if you try to print the variable varnames[1], it returns 'jan'.
To work around this, you need to do
print(get(varnames[1]))
If you want to convert string to variable inside body of function, but you want to have variable global:
test <- function() {
do.call("<<-",list("vartest","xxx"))
}
test()
vartest
[1] "xxx"
Maybe I didn't understand your problem right, because of the simplicity of your example. To my understanding, you have a series of instructions stored in character vectors, and those instructions are very close to being properly formatted, except that you'd like to cast the right member to numeric.
If my understanding is right, I would like to propose a slightly different approach, that does not rely on splitting your original string, but directly evaluates your instruction (with a little improvement).
original_string <- "variable_name=\"10\"" # Your original instruction, but with an actual numeric on the right, stored as character.
library(magrittr) # Or library(tidyverse), but it seems a bit overkilled if the point is just to import pipe-stream operator
eval(parse(text=paste(eval(original_string), "%>% as.numeric")))
print(variable_name)
#[1] 10
Basically, what we are doing is that we 'improve' your instruction variable_name="10" so that it becomes variable_name="10" %>% as.numeric, which is an equivalent of variable_name=as.numeric("10") with magrittr pipe-stream syntax. Then we evaluate this expression within current environment.
Hope that helps someone who'd wander around here 8 years later ;-)
Other than assign, one other way to assign value to string named object is to access .GlobalEnv directly.
# Equivalent
assign('abc',3)
.GlobalEnv$'abc' = 3
Accessing .GlobalEnv gives some flexibility, and my use case was assigning values to a string-named list. For example,
.GlobalEnv$'x' = list()
.GlobalEnv$'x'[[2]] = 5 # works
var = 'x'
.GlobalEnv[[glue::glue('{var}')]][[2]] = 5 # programmatic names from glue()
This question already has an answer here:
Function argument matching: by name vs by position
(1 answer)
Closed 2 years ago.
I have just started learning R and I am a little confused by the inputs to functions.
I see for example sqrt(9) and sqrt(x=9) being used interchangeably, and I don't understand why you would include the x=.
When passing arguments to a function in R, you can do it one of two ways:
By position
By name
In the case of sqrt(), it would never matter; there's only one argument, x. So, let's think about a function with multiple arguments where this could potentially matter:
foo <- function(a, b) a^b
a <- 2
b <- 3
foo(a, b)
# [1] 8
foo(b, a)
# [1] 9
foo(b = b, a = a)
# [1] 8
This illustrates one reason why you might want to name your arguments instead of just passing by position; it ensures that you're always giving the values to each argument that you think you are. Another reason to name arguments is for readability for those reading you're code who may not know what the arguments of a function you're using are.
For those reasons, some would say it's good practice to name your arguments even perhaps in a situation (like maybe sqrt()) where it might seem unnecessary. Although I generally err on the side of passing arguments to functions by name rather than position, IMO it's a little overkill for something like sqrt().
I know the function get can help you transform values to variable names, like get(test[1]). But I find it is not compatible when the values is in a list format. Look at below example:
> A = c("obj1$length","obj1$width","obj1$height","obj1$weight")
> obj1 <- NULL
> obj1$length=c(1:4);obj1$width=c(5:8);obj1$height=c(9:12);obj1$weight=c(13:16)
> get(A[1])
Error in get(A[1]) : object 'obj1$length' not found
In this case, how can I retrieve the variable name?
get doesn't work like that you need to specify the variable and environment (the list is coerced to one) separately:
get("length",obj1)
[1] 1 2 3 4
Do do it with the data you have, you need to use eval and parse:
eval(parse(text=A[1]))
[1] 1 2 3 4
However, I suggest you rethink your approach to the problem as get, eval and parse are blunt tools that can bite you later.
I think that eval() function will do the trick, among other uses.
eval(A[1])
>[1] 1 2 3 4
You could also find useful this simple function I implemented (based in the commonly used combo eval, parse, paste):
evaluate<-function(..., envir=.GlobalEnv){ eval(parse(text=paste( ... ,sep="")), envir=envir) }
It concatenates and evaluates several character type objects. If you want it to be used inside another function, add at the begining of your function
envir <- environment()
and use it like this:
evaluate([some character objects], envir=envir)
Try, for example
myvariable1<-"aaa"; myvariable2<-"bbb"; aaa<-15; bbb<-3
evaluate(myvariable1," * ",myvariable2).
I find it very usefull when I have to evaluate similar sentences with several variables, or when I want to create variables with automatically generated names.
for(i in 1:100){evaluate("variable",i,"<-2*",i)}
Is there a way to use get() with a list object?
The functionality I'm looking for is akin to:
x <- list(a=c(1,2,3),b=c(4,5,6),c=c(7,8,9))
get(paste("x$a",sep=""))
This will work:
get("a", envir=list2env(x))
But that is more or less as useful as x[['a']]. It seems you might also be looking for the eval/parse route:
eval(parse(text="x$a"))
Specify the pos= argument:
> get("a",x)
[1] 1 2 3
In order for your example to work, you would need to evaluate the expression, since "x$a" isn't a valid name.
> eval(parse(text=paste("x$a",sep="")))
[1] 1 2 3
Maybe this alternative would work for you?
get("x")[["a"]]
I am new to R programming. After checking some tutorial I picked up most things I needed, but one thing is still missing: the data structure map.
Does everybody know if R has dict? In which I can store (key, value) pairs?
Thanks!!
Yes it does and it is called list.
> x <- list(a=1, b="foo", c=c(1,1,2,3,5))
> x
$a
[1] 1
$b
[1] "foo"
$c
[1] 1 1 2 3 5
In Python it is called dict, for what it's worth.
Environments are also a candidate, and in many cases the best option.
e<-new.env(hash=T)
e$a<-1
e$b<-2
R> e$a
[1] 1
The disadvantage of a list is that it is a linear search.
There is the hash package..
Since array/vector elements can be named, you get some of the properties of a map/dictionary builtin.
x <- c(apple = 1, banana = 99, "oranges and lemons" = 33)
x["apple"]
x[c("bananas", "oranges and lemons")]
x[x == 99]
(If your values are of different types, then you need to use a list instead of a vector.)
The hash package as aforementioned does add a little overhead but does provide a flexible, intuitive methods for accessing the map/hash/dictionary. It should be very easy for users from another language to grok it.
A list is the best solution if the list has a small number of elements. (<200 or so).
An environment is best to use if you absolutely cannot tolerate a little overhead AND you do not want the flexible, intuitive methods.
The hash package is the best in most situations.
C-