Convert a vector into a specialised list efficiently - r

I'm looking for a more efficient way to get from my current input to my expected output.
Input
vec <- 1:4
Expected output
[[1]]
[1] 1 2 3 4
[[2]]
[1] 1
[[3]]
[1] 2
[[4]]
[1] 3
[[5]]
[1] 4
Current solution:
lis <- list()
lis[2:5] <- as.list(vec)
lis[[1]] <- vec

We can do
c(list(vec), as.list(vec))
#[[1]]
#[1] 1 2 3 4
#[[2]]
#[1] 1
#[[3]]
#[1] 2
#[[4]]
#[1] 3
#[[5]]
#[1] 4

Related

How to turn a vector into a list with known nest structure in R?

I want to turn a x dimensional vector into a nested list that has x elements. The nested list should have the same nest structure as a known list. Is there a simple way to do this?
For example, the vector to be transformed is
vector <- rnorm(10)
while the list with known structure is
list <- list( list(rnorm(2),rnorm(2)),
list(rnorm(3),rnorm(3)) )
[[1]]
[[1]][[1]]
[1] -1.113833 1.158779
[[1]][[2]]
[1] 0.09773685 -1.62518666
[[2]]
[[2]][[1]]
[1] -1.134478 -1.091703 -0.109145
[[2]][[2]]
[1] -0.5181986 -1.9268952 -0.8527101
Another similar situation is that I may know the length of each sublist
length_list <- list( list(2,2), list(3,3) )
You can use relist.
x <- 1:10
lst <- list( list(rnorm(2),rnorm(2)),
list(rnorm(3),rnorm(3)) )
relist(x, lst)
#[[1]]
#[[1]][[1]]
#[1] 1 2
#
#[[1]][[2]]
#[1] 3 4
#
#
#[[2]]
#[[2]][[1]]
#[1] 5 6 7
#
#[[2]][[2]]
#[1] 8 9 10
Or for the other case create a list with rapply.
x <- 1:10
length_list <- list( list(2,2), list(3,3) )
relist(x, rapply(length_list, rep, x=0, how="list"))
#[[1]]
#[[1]][[1]]
#[1] 1 2
#
#[[1]][[2]]
#[1] 3 4
#
#
#[[2]]
#[[2]][[1]]
#[1] 5 6 7
#
#[[2]][[2]]
#[1] 8 9 10

How to merge two lists based on object indices - keeping attributes?

I want to merge two lists keeping the index of each object:
mylist<-list(1,NULL,2)
otherlist<-list(NULL,3,NULL,4,5,6)
# Desired
list(1,3,2,4,5,6)
# my try:
suppressWarnings(mapply(c, mylist, otherlist) )
Answer should be universal
EDIT: In order to avoid proliferation of similar questions. I decided to request here also the possibility of keeping attributes (preferably with base).
mylist<-list(1,NULL,2)
attr(mylist[[1]],"at")<-"a"
attr(mylist[[3]],"at")<-"c"
otherlist<-list(NULL,3,NULL,4,5,6)
attr(otherlist[[2]],"at")<-"b"
attr(otherlist[[4]],"at")<-"d"
attr(otherlist[[5]],"at")<-"e"
attr(otherlist[[6]],"at")<-"f"
Here is an option where we create a logical index with lengths (which will return 0 when there is NULL) and use to assign the elements with mylist unlisted
otherlist[lengths(otherlist) == 0] <- unlist(mylist)
otherlist
#[[1]]
#[1] 1
#[[2]]
#[1] 2
#[[3]]
#[1] 3
#[[4]]
#[1] 4
#[[5]]
#[1] 5
#[[6]]
#[1] 6
If we need to use Map, make sure the lengths are the same for the corresponding elements
otherlist[seq_along(mylist)] <- Map(c, otherlist[seq_along(mylist)], mylist)
Update
For the updated example
i1 <- sapply(otherlist, is.null)
i2 <- !sapply(mylist, is.null)
otherlist[i1] <- mylist[i2]
otherlist
#[[1]]
#[1] 1
#attr(,"at")
#[1] "a"
#[[2]]
#[1] 3
#attr(,"at")
#[1] "b"
#[[3]]
#[1] 2
#attr(,"at")
#[1] "c"
#[[4]]
#[1] 4
#attr(,"at")
#[1] "d"
#[[5]]
#[1] 5
#attr(,"at")
#[1] "e"
#[[6]]
#[1] 6
#attr(,"at")
#[1] "f"
foo <- function(l1, l2) {
out <- vector(mode = "list", length = max(length(l1), length(l2)))
out[seq_along(l1)] <- l1
out[!lengths(out)] <- l2[!lengths(out)]
out
}
foo(mylist, otherlist2)
# [[1]]
# [1] 1
# attr(,"at")
# [1] "a"
#
# [[2]]
# [1] 3
# attr(,"at")
# [1] "b"
#
# [[3]]
# [1] 2
# attr(,"at")
# [1] "c"
#
# [[4]]
# [1] 5
# attr(,"at")
# [1] "e"
#
# [[5]]
# [1] 6
# attr(,"at")
# [1] "f"

Convert each row of dataframe to new list in R

I have below sample input data-
> df <- data.frame(a=c(1,2,9),b=c(3,4,5),c=c(2,6,7))
> df
a b c
1 1 3 2
2 2 4 6
3 9 5 7
I am trying to convert rach row into separate list.
My Attempt-
> apply(df,1,as.list)
The above solution converts each row into sublists. But, I am looking for 3 separate list in this case.
nrow(df) = no. of lists
Desired Output-
> list1
$a
[1] 1
$b
[1] 3
$c
[1] 2
> list2
$a
[1] 2
$b
[1] 4
$c
[1] 6
> list3
$a
[1] 9
$b
[1] 5
$c
[1] 7
You can use by and as.list
out <- by(df, 1:nrow(df), as.list)
out
#1:nrow(df): 1
#$a
#[1] 1
#
#$b
#[1] 3
#$c
#[1] 2
#------------------------------------------------------------------------------
#1:nrow(df): 2
#$a
#[1] 2
#$b
#[1] 4
#$c
#[1] 6
#------------------------------------------------------------------------------
#1:nrow(df): 3
#$a
#[1] 9
#$b
#[1] 5
#$c
#[1] 7
That creates an object of class by. So you may call unclass(out) in the end.

Replacing values in a list based on a condition

I have a list of values called squares and would like to replace all values which are 0 to a 40.
I tried:
replace(squares, squares==0, 40)
but the list remains unchanged
If it is a list, then loop through the list with lapply and use replace
squares <- lapply(squares, function(x) replace(x, x==0, 40))
squares
#[[1]]
#[1] 40 1 2 3 4 5
#[[2]]
#[1] 1 2 3 4 5 6
#[[3]]
#[1] 40 1 2 3
data
squares <- list(0:5, 1:6, 0:3)
I think for this purpose, you can just treat it as if it were a vector as follows:
squares=list(2,4,6,0,8,0,10,20)
squares[squares==0]=40
Output:
[[1]]
[1] 2
[[2]]
[1] 4
[[3]]
[1] 6
[[4]]
[1] 40
[[5]]
[1] 8
[[6]]
[1] 40
[[7]]
[1] 10
[[8]]
[1] 20

Reverse sort list by max element

I have a list of vectors
l = list(c(1,2),c(3,4),c(2,3),c(7,8),c(5,6))
and would to reverse sort it by the vector maximums:
> l
[[1]]
[1] 7 8
[[2]]
[1] 5 6
[[3]]
[1] 3 4
[[4]]
[1] 2 3
[[5]]
[1] 1 2
Any idea how I could do this in a one liner? thx
One way is
l[order(sapply(l, max), decreasing=TRUE)]
#[[1]]
#[1] 7 8
#[[2]]
#[1] 5 6
#[[3]]
#[1] 3 4
#[[4]]
#[1] 2 3
#[[5]]
#[1] 1 2
You could replace sapply(l, max) with vapply(l, max, numeric(1L)) as well.
Or a compact form suggested by #DavidArenburg
l[order(-sapply(l, max))]

Resources