In R operators can also be expressed as a function call, e.g.
'<-'(b, 12)
for b <- 12.
Why does the following give an error:
'->'(12, b)
? (The code 12 -> b works as expected.)
Because operators are "translated" to functions by the parser and both left and right assignment are parsed to the <- function. There is no right assignment function.
e <- quote(b <- 12)
as.list(e)
#[[1]]
#`<-`
#
#[[2]]
#b
#
#[[3]]
#[1] 12
e <- quote(12 -> b)
as.list(e)
#[[1]]
#`<-`
#
#[[2]]
#b
#
#[[3]]
#[1] 12
Related
I have a list of named elements that I want to transform into a named list of those elements:
el1 = c(a = 1)
el2 = c(b = 2)
b = list(el1, el2)
What I want is something like a = list(a = 1, b = 2)
so that identical(a, b) returns TRUE
Is there a transformation I can apply to b to do this? I tried a combination of unlist/unname but didn't seem like that got my any closer.
We can use as.list after concatenating the named vectors
b <- as.list(c(el1, el2))
b
#$a
#[1] 1
#$b
#[1] 2
identical(a, b)
#[1] TRUE
Also, if the list is already created as in the OP's post, unlist and use as.list
b <- list(el1, el2)
b <- as.list(unlist(b))
identical(a, b)
#[1] TRUE
Here is another base R option, but not as simple as the solution by akrun
> do.call(c,Map(as.list,b))
$a
[1] 1
$b
[1] 2
Sadly was unable to realize how to do it in R, but the idea seams simple.
What I want is a list of pairs of numbers under a range where the fist pair is the first value and the sum of first pair with the maximum length, in the end I should have something like:
somefun <- function(start, end, step){...}
l <- somefun (5, 30, 5)
l
#[[1]]
#[[1]][[1]]
#[1] 5
#
#[[1]][[2]]
#[1] 10
#
#[[2]]
#[[2]][[1]]
#[1] 11
#
#[[2]][[2]]
#[1] 16
#
#[[3]]
#[[3]][[1]]
#[1] 17
#
#[[3]][[2]]
#[1] 22
#
#[[4]]
#[[4]][[1]]
#[1] 23
#
#[[4]][[2]]
#[1] 28
#
#[[5]]
#[[5]][[1]]
#[1] 29
#[[5]][[2]]
#[1] 30
So, the final list should have the first start and the last end values, but the difference within each list shouldn't be larger than the step.
Also, I don't know if it could be the best way, but my objective is pass this values with lapply to build a plot using grid with gredExtra::grid.arrange
So the list should fit in this code
p_list = lapply(myRanges, function(a,b){
my_gg_function(myData[a:b], font=f)
})
do.call(gridExtra::grid.arrange, c(p_list, ncol=2))
Thanks in advance
How about this
somefun <- function(start, end, step){
starts <- seq(start, end, step+1)
ends <- pmin(starts + step, end)
mapply(list, starts, ends, SIMPLIFY = FALSE)
}
somefun(5, 30, 5)
We just use a basic seq() and trim as needed.
I would like to subset an environment by its variable names.
e <- new.env(parent=emptyenv())
e$a <- 1
e$b <- 2
e$d <- 3
e[ls(e) %in% c("a","b", "c")]
### if e was a list, this would return the subset list(a=1, b=2)
I could not figure out how to subset elements of an environment by their names. Using lapply or eapply does not work either. What is the proper or easy way to subset an environment by its variable names?
Thank you.
Okay, after thinking this through a bit more, may I suggest:
mget(c("a","b"), envir=e)
#$a
#[1] 1
#
#$b
#[1] 2
My original solution is to use get() / mget() (maybe OP saw my deleted comment earlier). Then I noticed that OP had tried eapply(), so I thought about possible solutions with that. Here it is (with help of #thelatemail).
# try some different data type
e <- new.env(parent=emptyenv())
e$a <- 1:3
e$b <- matrix(1:4, 2)
e$c <- data.frame(x=letters[1:2],y=LETTERS[1:2])
You can use either of the following to collect objects in environment e into a list:
elst <- eapply(e, "[") ## my idea
elst <- eapply(e, identity) ## thanks to #thelatemail
elst <- as.list.environment(e) ## thanks to #thelatemail
#$a
#[1] 1 2 3
#$b
# [,1] [,2]
#[1,] 1 3
#[2,] 2 4
#$c
# x y
#1 a A
#2 b B
The as.list.environment() can be seen as the inverse operation of list2env(). It is mentioned in the "See Also" part of ?list2env.
The result elst is just an ordinary list. There are various way to subset this list. For example:
elst[names(elst) %in% c("a","b")] ## no need to use "ls(e)" now
#$a
#[1] 1 2 3
#$b
# [,1] [,2]
#[1,] 1 3
#[2,] 2 4
mget(ls(e)[ls(e) %in% c('a','b','d')], e)
The [ operator usually returns the same type of object as the original, so I guess you're expecting an environment, rather than a list. The same environment but with a different set of elements, or a new environment with the specified elements? Either way I think you'll end up iterating, e.g.,
f = new.env(parent=emptyenv())
for (elt in c("a", "b"))
f[[elt]] = e[[elt]]
Working with environments is not very idiomatic R code, which might explain why there is not a more elegant solution.
You can use rlang::env_get_list() to get a list of the bindings:
rlang::env_get_list(env=e, c("a","b"))
#$a
#[1] 1
#
#$b
#[1] 2
If you're trying to get an environment, rather than a list, I'm not sure how you would do that, other than just creating a new environment using the output of rlang::env_get_list().
If you want to include elements in your list that might not exist in the environment (like "c"), you have to specify a default value - otherwise you'll get an error:
env_get_list(env = e, c("a","b","c"))
#Error in env_get_list(env = e, c("a", "b", "c")) : argument "default" is missing, with no default
env_get_list(env = e, c("a","b","c"),default=NULL)
#$a
#[1] 1
#
#$b
#[1] 2
#
#$c
#NULL
I assume you don't want c at all, so I'd do something like:
temp <- c("a","b","c")[c("a","b","c") %in% env_names(e)]
temp
[1] "a" "b"
env_get_list(env=e,temp)
#$a
#[1] 1
#
#$b
#[1] 2
I want to include a list element c in a list L in R and name it C.
The example is as follows:
a=c(1,2,3)
b=c("a","b","c")
c=rnorm(3)
L<-list(A=a,
B=b,
C=c)
print(L)
## $A
## [1] 1 2 3
##
## $B
## [1] "a" "b" "c"
##
## $C
## [1] -2.2398424 0.9561929 -0.6172520
Now I want to introduce a condition on C, so it is only included in
the list if C.bool==T:
C.bool<-T
L<-list(A=a,
B=b,
if(C.bool) C=c)
print(L)
## $A
## [1] 1 2 3
##
## $B
## [1] "a" "b" "c"
##
## [[3]]
## [1] -2.2398424 0.9561929 -0.6172520
Now, however, the list element of c is not being named as specified in
the list statement. What's the trick here?
Edit: The intention is to only include the element in the list if the condition is met (no NULL shoul be included otherwise). Can this be done within the core definition of the list?
I don't know why you want to do it "without adding C outside the core definition of the list?" but if you're content with two lists in a single c then:
L <- c(list(A=a, B=b), if(C.bool) list(C=c))
If you really want one list but don't mind subsetting after creation then
L <- list(A=a, B=b, C=if(C.bool) c)[c(TRUE, TRUE, C.bool)]
(pace David Arenburg, isTRUE() omitted for brevity)
you can try this if you want to keep the names
L2 <-list(A=a,
B=b,
C = if (TRUE) c)
You can of course replace TRUE with the statement containing C.bool
You could place the if statement outside the core definition of the list, like this:
L <- list(A = a, B= b)
if (isTRUE(C.bool)) L$C <- c
#> L
#$A
#[1] 1 2 3
#
#$B
#[1] "a" "b" "c"
#
#$C
#[1] -0.7631459 0.7353929 -0.2085646
(Edit with isTRUE() owing to the comment by #DavidArenburg)
As a combination of the previous answers by #MamounBenghezal, #user20637
and the comment made by #DavidArenburg, I would suggest this generalized
version that does not depend on the length of the list:
L <- Filter(Negate(is.null),
x = list(A = a, B = b, C = if (isTRUE(C.bool)) c, D = "foo"))
I am using matching operators to grab values that appear in a matrix from a separate data frame. However, the resulting matrix has the values in the order they appear in the data frame, not in the original matrix. Is there any way to preserve the order of the original matrix using the matching operator?
Here is a quick example:
vec=c("b","a","c"); vec
df=data.frame(row.names=letters[1:5],values=1:5); df
df[rownames(df) %in% vec,1]
This produces > [1] 1 2 3 which is the order "a" "b" "c" appears in the data frame. However, I would like to generate >[1] 2 1 3 which is the order they appear in the original vector.
Thanks!
Use match.
df[match(vec, rownames(df)), ]
# [1] 2 1 3
Be aware that if you have duplicate values in either vec or rownames(df), match may not behave as expected.
Edit:
I just realized that row name indexing will solve your issue a bit more simply and elegantly:
df[vec, ]
# [1] 2 1 3
Use match (and get rid of the NA values for elements in either vector for those that don't match in the other):
Filter(function(x) !is.na(x), match(rownames(df), vec))
Since row name indexing also works on vectors, we can take this one step further and define:
'%ino%' <- function(x, table) {
xSeq <- seq(along = x)
names(xSeq) <- x
Out <- xSeq[as.character(table)]
Out[!is.na(Out)]
}
We now have the desired result:
df[rownames(df) %ino% vec, 1]
[1] 2 1 3
Inside the function, names() does an auto convert to character and table is changed with as.character(), so this also works correctly when the inputs to %ino% are numbers:
LETTERS[1:26 %in% 4:1]
[1] "A" "B" "C" "D"
LETTERS[1:26 %ino% 4:1]
[1] "D" "C" "B" "A"
Following %in%, missing values are removed:
LETTERS[1:26 %in% 3:-5]
[1] "A" "B" "C"
LETTERS[1:26 %ino% 3:-5]
[1] "C" "B" "A"
With %in% the logical sequence is repeated along the dimension of the object being subsetted, this is not the case with %ino%:
data.frame(letters, LETTERS)[1:5 %in% 3:-5,]
letters LETTERS
1 a A
2 b B
3 c C
6 f F
7 g G
8 h H
11 k K
12 l L
13 m M
16 p P
17 q Q
18 r R
21 u U
22 v V
23 w W
26 z Z
data.frame(letters, LETTERS)[1:5 %ino% 3:-5,]
letters LETTERS
3 c C
2 b B
1 a A