Skip to content

Using assign with mapply

7 messages · David Winsemius, Greg Snow, Julio Sergio Santana

#
I have a data frame whose first colum contains the names of the variables 
and whose second colum contains the values to assign to them:

   : kkk <- data.frame(vars=c("var1", "var2", "var3"), 
                     vals=c(10, 20, 30), stringsAsFactors=F)

If I do 

   : assign(kkk$vars[1], kkk$vals[1])

it works

   : var1
   [1] 10

However, if I try with mapply this is what I get:

   : mapply(assign, kkk$vars, kkk$vals)
   var1 var2 var3 
     10   20   30 
   : var2
   Error: object 'var2' not found

Maybe I have not undestand how mapply and assign work. Do you have
any comments?

Thanks,

  -Sergio.
#
On Dec 6, 2013, at 11:27 AM, Julio Sergio Santana wrote:

            
I think you will find that the value returned from the mapply call was a three element list with the desired names and values  ... except you then gave that enclosing list no name and it will be garbage-collected. If you want to have 'assign' do its magic into the global environment, then you need to supply 'mapply' a MoreArgs argument on the other side of the ellipsis:

Usage:
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE,
       USE.NAMES = TRUE)

So what happens if you try this:

mapply(assign,  kkk$vars, kkk$vals, MoreArgs = list(envir = .GlobalEnv)
3 days later
#
David Winsemius <dwinsemius <at> comcast.net> writes:
Yes, it works in certain situations, as well as the equivalent code:

     kkk <- data.frame(vars=c("var1", "var2", "var3"), 
                  vals=c(10, 20, 30), stringsAsFactors=F)

     mapply(assign,  kkk$vars, kkk$vals, MoreArgs = list(pos = 1))
     var1
    [1] 10

See, however, the following example

    : example <- function () {
        var1 <- 250
        kkk <- data.frame(vars=c("var1", "var2", "var3"), 
                      vals=c(10, 20, 30), stringsAsFactors=F)
        mapply(assign,  kkk$vars, kkk$vals, MoreArgs = list(pos = 1))
        print (var2)
        print (var1)
      }
 
      example()
     [1] 20
     [1] 250

My question is: how to get the combination of mapply and assign to affect 
the variables defined in the block where the construction is executed?

Maybe there is still something I don't understand.


Thanks,

  -Sergio.
6 days later
#
Julio Sergio Santana <juliosergio <at> gmail.com> writes:
For those interested in the problem this is how I solved the problem:


I want to have something similar to:
#
#   var1 <- 10
#   var2 <- 20
#   var3 <- 30

my first trial was:

   mapply(assign,  kkk$vars, kkk$vals)
## var1 var2 var3 
## 10   20   30 
#

This is, however, what I got:

   var1
## Error: object 'var1' not found

David Winsemius suggested me something similar to 


   mapply(assign,  kkk$vars, kkk$vals, MoreArgs = list(pos = 1))
# or:
   mapply(assign,  kkk$vars, kkk$vals, MoreArgs = list(envir = .GlobalEnv))

var1
## [1] 10

This almost works, but what if this construction is used inside a function?

   example <- function () {
      var1 <- 250
      kkk <- data.frame(vars=c("var1", "var2", "var3"), 
                        vals=c(10, 20, 30), stringsAsFactors=F)
     mapply(assign,  kkk$vars, kkk$vals, MoreArgs = list(pos = 1))
     print (var2)
     print (var1)
   }

   example()
## [1] 20
## [1] 250

var1, which was defined inside the function, isn't modified

To fix this, I defined the function as follows: 

   example <- function () {
     var1 <- 250
     kkk <- data.frame(vars=c("var1", "var2", "var3"), 
                       vals=c(10, 20, 30), stringsAsFactors=F)
     mapply(assign,  kkk$vars, kkk$vals, 
            MoreArgs = list(pos = sys.frame(sys.nframe())))
     # sys.nframe() is the number of the frame created inside the function
     # and sys.frame() establishes it as the one assign uses to set values
     print (var2)
     print (var1)
   }

   example()
## [1] 20
## [1] 10

And the purpose is got

Thanks,

  -Sergio.
2 days later
#
The take home message that you should be learning from your struggles
is to "Not Use The 'assign' Function!" and "Do Not Use Global
Variables Like This".

R has lists (and environments) that make working with objects that are
associated with each other much simpler and fits better with the
functional programming style of R.

For example you can create a list from your data frame quickly and
easily with code like:

mydata <- as.list(kkk$vals)
names(mydata) <- kkk$vars

or

mydata <- setNames( as.list(kkk$vals), kkk$vars )

then you will have you variables (with names) inside the list (mydata
in this example, but name it whatever you want)

This list can then be passed out of a function or otherwise used.

To access a specific variable by name you can do:

mydata$var1

or

mydata[['var2']]

or

with(mydata, var3)

but you can also do things like (and this is often a follow-up
question to questions like yours):

varname <- 'var3'
mydata[[ varname ]]

and you can also use lapply and sapply to do the same action on every
variable in your list:

sapply( mydata, function(x) x + 5 )

instead of having to loop through a bunch of global variables.

And if you want to save or delete these, now you just save or delete
the entire list rather than having to loop through the set of global
variables.

If you tell us more about how you want to use these variables we can
give more suggestions, but the main point is that in the long run you
will be happier learning to use lists (and possibly environments) in
place of trying to create and work with global variables like you
asked about.




On Mon, Dec 16, 2013 at 8:55 AM, Julio Sergio Santana
<juliosergio at gmail.com> wrote:

  
    
#
Greg Snow <538280 <at> gmail.com> writes:
Thanks, Greg!

Yours is a very smart solution to the problem I posed. 

By the way, what I'm trying to do is reading from a file a set of user given 
parameters, in two paired columns: parameter-name, value; and then, managing 
these parameters inside my R program. Now I do understand a bit more about 
lists. What about environments? Are they similar to lists, and when, and how 
are they created?

Best regrards,

  -Sergio.
#
Trying to understand environments is not for the faint of heart.  If
lists do what you want then I would stick with a list and not worry
about the environments.  Most of the time that you deal with
environments everything happens automatically behind the scenes and
you don't need to worry about the details.

If you want to learn more about environments there here is a start.
Many of the ways of working with environments is the same as working
with lists (you can access and assign with `[[` etc.) and there are
`as.` functions to convert between them.  The biggest difference is
that environments use references instead of copies (powerful but
dangerous).  If you do something like

mylist2 <- mylist
mylist2$x <- 1

then mylist 2 will be a copy of mylist 1 and the value of x within
mylist2 will be created or modified (but mylist will remain
unchanged).  However if you do the same thing with an environment then
a copy is not made and the `x` variable in the original environment
will be created or changed.  This can be a big benefit when you have a
large data object that needs to be passed to multiple functions, with
an environment the data will never be copied, with a list or other
object you may end up with multiple copies (though R is really good at
not making copies when it does not need to, but sometimes you still
end up with more copies than needed when R cannot tell if a copy is
needed or not), but this is dangerous in that if you make any changes
then the original is changed as well (the regular mechanism of making
copies on changes protects the original).

Environments also use hashing for name look ups which can speed things
up when you have a large number of variables that you are accessing by
name (but most usual cases are quick enough that you will not notice
when using lists or other objects).

Hope that helps,

On Thu, Dec 19, 2013 at 10:17 AM, Julio Sergio Santana
<juliosergio at gmail.com> wrote: