I have two lists with named elements:
a <- list(a=1, b=2)
b <- list(b=3, c=4)
I want to combine these lists, so that any elements in a that have the same names will be overwritten by the list b, so I get this out:
list(a=1, b=3, c=4)
I know I could do this in a loop, but is there a more compact way of doing this in R?
R has a built in function to do that modifyList
modifyList(a, b)
Here's a simple solution:
# create new list
newlist <- c(a,b)
# remove list element(s)
newlist[!duplicated(names(newlist), fromLast = TRUE)]
The result:
$a
[1] 1
$b
[1] 3
$c
[1] 4
An even simpler solution with setdiff:
c(a[setdiff(names(a), names(b))], b)
$a
[1] 1
$b
[1] 3
$c
[1] 4
Related
I have a list of lists:
library(partitions)
list_parts(3)
>[1] (1,2,3)
>[[2]]
>[1] (1,3)(2)
>[[3]]
>[1] (1,2)(3)
>[[4]]
>[1] (2,3)(1)
>[[5]]
>[1] (1)(2)(3)
I need to filter out certain lists based on combinations as they are not feasible. For example list[4] is not possible because (2,3) cannot be a list without (1). How can I filter based on a combination rule set eg remove combinations where 2 and 3 are in a list without 1?
We can borrow the method from this answer to Find vector in list of vectors and wrap it in our own function.
library(partitions)
p = listParts(3)
detect = function(p, pattern) {
Position(function(x) identical(x, pattern), p, nomatch = 0) > 0
}
test = sapply(p, detect, pattern = 2:3)
p[!test]
# [[1]]
# [1] (1,2,3)
#
# [[2]]
# [1] (1,3)(2)
#
# [[3]]
# [1] (1,2)(3)
#
# [[4]]
# [1] (1)(2)(3)
Assume I have this list of vectors:
mylist <- list(a=1:3,b=4:1,c=1:5)
mylist
$a
[1] 1 2 3
$b
[1] 4 3 2 1
$c
[1] 1 2 3 4 5
I want to get the last or the max element of each vector like this for the last element:
$a
[1] 3
$b
[1] 1
$c
[1] 5
What I have tried so far:
First use lapply and the length function to get the last element index and then subset:
last <- unlist(lapply(mylist, length))
lapply(mylist,"[", last) # not working
Then I tried to use sapply with lapply. This is working, but I'm not sure whether this is generally valid. There must be a better base R solution (without loops!).
mymatrix <- sapply(last, function(x) lapply(mylist, "[",x))
diag(mymatrix)
$a
[1] 3
$b
[1] 1
$c
[1] 5
(Making this a CV as there were many contributes here and worth summing this up)
If you have some function you want to apply on your list, a simple lapply should do, such as
lapply(mylist, max) # retrieving the maximum values
Or
lapply(mylist, tail, 1) # retrieving the last values (by #docendo)
If you want to operate on two vectors simultaneously, you could use mapply or Map
Map(`[`, mylist, lengths(mylist)) # A Map version of #docendos lapply suggestion
Or per your newest request
Map(`[`, mylist, 1:3)
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"))
If I was starting with a list A that contained lists N and M, which contain equal number of elements:
A = list( N=list( a=c(1,1), b=c(2,2)),
M=list( a=c(1,1), b=c(2,2)) )
I would do the following to combine each of the elements from the lists N and M into new lists
B = mapply( FUN=list, A[[1]], A[[2]], SIMPLIFY=FALSE )
to get
>B
$a
$a[[1]]
[1] 1 1
$a[[2]]
[1] 1 1
$b
$b[[1]]
[1] 2 2
$b[[2]]
[1] 2 2
How can I do the same thing as above if I don't know beforehand the number of lists that the list A will have?
There is probably a better solution to your problem, but if you literally want to "do the same thing, but without knowing size of A", you can do the following:
do.call(function(...) mapply(..., FUN = list, SIMPLIFY = FALSE), A)
try using tapply:
tapply(U, inds, list)
Where
U <- unlist(A, recursive=FALSE)
inds <- rep(seq_along(A[[1]]), length(A))
I have two lists with named elements:
a <- list(a=1, b=2)
b <- list(b=3, c=4)
I want to combine these lists, so that any elements in a that have the same names will be overwritten by the list b, so I get this out:
list(a=1, b=3, c=4)
I know I could do this in a loop, but is there a more compact way of doing this in R?
R has a built in function to do that modifyList
modifyList(a, b)
Here's a simple solution:
# create new list
newlist <- c(a,b)
# remove list element(s)
newlist[!duplicated(names(newlist), fromLast = TRUE)]
The result:
$a
[1] 1
$b
[1] 3
$c
[1] 4
An even simpler solution with setdiff:
c(a[setdiff(names(a), names(b))], b)
$a
[1] 1
$b
[1] 3
$c
[1] 4