Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning multiple values to an environment at once

Given an environment x, a convenient shorthand for assign(x, value, envir = e) is to write e[[x]] <- value. Currently, there is not an analog to the subset operator for assigning multiple objects at once:

> e = new.env(parent = emptyenv())
> e[["a"]] <- 1
> ls(e)
[1] "a"
> e[c("b", "c")] <- c(1,2)
Error in e[c("b", "c")] <- c(1, 2) : 
  object of type 'environment' is not subsettable

I was hoping to write one using the built in S3 functionality for [<-. The first oddity I noticed was that both [[<- and [<- are primitive functions despite imitating S3 functions:

> methods("[<-")
[1] [<-.data.frame  [<-.Date        [<-.environment [<-.factor      [<-.POSIXct     [<-.POSIXlt     [<-.raster*     [<-.ts* 

Normally, S3 functions have the format where the body is just a call to UseMethod. For example:

> summary
function (object, ...) 
UseMethod("summary")
<bytecode: 0x1a7c3a8>
<environment: namespace:base>

In addition to the assignment operators being primitive, there is no S3 method for [[<- for class environment:

> methods(class = environment)
[1] as.list.environment

So the original assignment using [[<- must be done using the default, if there is such a default for a primitive function. Despite this, I implemented an S3 function for [<-.environment:

> `[<-.environment` = function(x, names, values) {
mapply(function(name, value) { x[[name]] <- value }, names, values) }

This appears to behave as if it were correctly implemented for the following:

> methods(class = environment)
[1] [<-.environment     as.list.environment
> methods(`[<-`)
[1] [<-.data.frame  [<-.Date        [<-.environment [<-.factor      [<-.POSIXct     [<-.POSIXlt     [<-.raster*     [<-.ts*  

However, it runs into the same error:

> e = new.env(parent = emptyenv())
> e[c("b", "c")] <- c(1,2)
Error in e[c("b", "c")] <- c(1, 2) : 
  object of type 'environment' is not subsettable

Could someone explain both the inconsistency with the S3 methods for [<- and [[<-, as well how to correctly implement subset assignment for environments?

like image 348
Jon Claus Avatar asked May 13 '14 21:05

Jon Claus


1 Answers

Here's a start, modified from ?list2env

L <- list(a = 1, b = 2:4, p = pi, ff = gl(3, 4, labels = LETTERS[1:3]))
e <- list2env(L)
addToEnv <- function(e, names, values) {
    l1 <- sapply(values, list)
    names(l1) <- names
    el1 <- mget(ls(e), envir=e)
    al1 <- as.list(c(el1, l1))
    return(list2env(al1))
    }
e2 <- addToEnv(e, names=letters[7:8], values=letters[9:10])
mget(ls(e2), envir=e2)

giving:

$a
[1] 1

$b
[1] 2 3 4

$ff
 [1] A A A A B B B B C C C C
Levels: A B C

$g
[1] "i"

$h
[1] "j"

$p
[1] 3.141593

I admit this isn't v. efficient, but should work for small sized environments.

like image 167
dardisco Avatar answered Sep 21 '22 13:09

dardisco