preserve list elements as names in lapply function - r

Say I have the following:
seq<-c(2,3,4)
added<-lapply(1:length(seq),function(i){
seq[i]+1
}
)
> added
[[1]]
[1] 3
[[2]]
[1] 4
[[3]]
[1] 5
How do I use the list elements in seq to name the list elements of 'added'?
i.e.
> added
[[2]]
[1] 3
[[3]]
[1] 4
[[4]]
[1] 5
thank you
ACCEPTED SOLUTION from #akrun
seq<-c(2,3,4)
added<-setNames(lapply(1:length(seq),function(i){
seq[i]+1
}
),seq1)

You could try
added <- setNames(added, seq)
Or
names(added) <- seq

library(purrr)
seq<-c(2,3,4)
set_names(seq, seq_along(seq))
or
seq %>%
set_names(seq_along(.))

Related

Add positional index to a list

I would like to add a sequential element onto a list. Suppose I have the following list
lst <- list("A"=list(e1="a",e2="!"), "B"=list(e1="b", e2="#"))
$A
$A$e1
[1] "a"
$A$e2
[1] "!"
$B
$B$e1
[1] "b"
$B$e2
[1] "#"
I would like to append a e3 which is the position index of that element in the list so essentially I would like my list to be:
$A
$A$e1
[1] "a"
$A$e2
[1] "!"
$A$e3
[1] 1
$B
$B$e1
[1] "b"
$B$e2
[1] "#"
$B$e3
[1] 2
setNames(lapply(seq_along(lst), function(i){
temp = lst[[i]]
temp$e3 = i
temp
}), names(lst))
#$`A`
#$`A`$`e1`
#[1] "a"
#$`A`$e2
#[1] "!"
#$`A`$e3
#[1] 1
#$B
#$B$`e1`
#[1] "b"
#$B$e2
#[1] "#"
#$B$e3
#[1] 2
Here is a solution that doesn't assume that the sub-lists have the same known number of elements.
library("tidyverse")
library("glue")
lst <- list("A"=list(e1="a",e2="!"), "B"=list(e1="b", e2="#"))
# The part
# `setNames(list(.y), glue("e{length(.x) + 1}"))`
# creates a one-element list named accordingly to append to the previous list
map2(lst, seq(lst),
~ append(.x, setNames(list(.y), glue("e{length(.x) + 1}") )))
#> $A
#> $A$e1
#> [1] "a"
#>
#> $A$e2
#> [1] "!"
#>
#> $A$e3
#> [1] 1
#>
#>
#> $B
#> $B$e1
#> [1] "b"
#>
#> $B$e2
#> [1] "#"
#>
#> $B$e3
#> [1] 2
# If naming the additional element is not important, then this can simplified to
map2(lst, seq(lst), append)
# or
map2(lst, seq(lst), c)
Created on 2019-03-06 by the reprex package (v0.2.1)
Another option using Map
Map(function(x, y) c(x, "e3" = y), x = lst, y = seq_along(lst))
#$A
#$A$e1
#[1] "a"
#$A$e2
#[1] "!"
#$A$e3
#[1] 1
#$B
#$B$e1
#[1] "b"
#$B$e2
#[1] "#"
#$B$e3
#[1] 2
This could be written even more concise as
Map(c, lst, e3 = seq_along(lst))
Thanks to #thelatemail
We can use a for loop as well
for(i in seq_along(lst)) lst[[i]]$e3 <- i
Assuming I understood correctly, that you want to add a 3rd element to each nested list which contains the index of that list in it's parent list. This works:
library(rlist)
lst <- list("A"=list(e1="a",e2="!"), "B"=list(e1="b", e2="#"))
for(i in seq(1:length(lst))){
lst[[i]] <- list.append(lst[[i]],e3=i)
}
lst
We can loop along the length of lst with lapply, adding this sequential index to each element.
lst2 <- lapply(seq_along(lst), function(i) {
df <- lst[[i]]
df$e3 <- i
return(df)
})
names(lst2) <- names(lst) # Preserve names from lst
Or, if you're not scared about modifying in place:
lapply(seq_along(lst), function(i) {
lst[[i]]$e3 <<- i
})
Both give the same output:
$A
$A$e1
[1] "a"
$A$e2
[1] "!"
$A$e3
[1] 1
$B
$B$e1
[1] "b"
$B$e2
[1] "#"
$B$e3
[1] 2

R extend vectors to be the same length around central value

Let's suppose I have a list:
[[1]]
[1] 0.7125856 -1.4871811 0.6230076 1.0756424 0.8172592 -0.1327926 -0.7674947 -1.0738684 1.5706677
[10] -0.6674960
[[2]]
[1] -0.5778682 -1.1186447 0.8272505 0.5123162 0.6607654 1.6559877 -0.7961859 -0.8966686
[[3]]
[1] -1.42867999 -0.21142100 -2.89762370 0.11036288 0.66846399 -0.77309213 0.35278541 -0.99579117 -0.73043142
[10] -0.01857864 -0.93654969 0.46751328
[[4]]
[1] -0.483896685 -0.207550362 -0.902920637 -0.008191134 -1.015636093
And I also have a vector with indices of so-called "central" values of vectors in this list:
[1] 2 4 5 1
What I'm trying to get is for given range (for example, 3) get subsets of vectors around those centers with the length of range in both sides. So every subset must be length of 7 and if range extends beyond length of vector there must be NAs added:
[[1]]
[1] NA NA 0.7125856 [-1.4871811] 0.6230076 1.0756424 0.8172592
[[2]]
[1] -0.5778682 -1.1186447 0.8272505 [0.5123162] 0.6607654 1.6559877 -0.7961859
[[3]]
[1] -0.2114210 -2.8976237 0.1103629 [0.6684640] -0.7730921 0.3527854 -0.9957912
[[4]]
[1] NA NA NA [-0.483896685] -0.207550362 -0.902920637 -0.008191134
I put centers in brackets, because SO doesn't allow bold text in a code. Is there a way to do something like this in R?
I think you're looking for something like this?
Data:
n <- 10
x <- list(rnorm(n),rnorm(n),rnorm(n),rnorm(n))
i <- c(2,4,5,1)
r <- 3
Possible solution:
f <- function(x) ifelse((x-r):(x+r) %in% 1:n,(x-r):(x+r),NA)
tmp <- lapply(i,f)
out <- mapply("[",x,tmp)
split(out,col(out))
$`1`
[1] NA NA 0.8120232 0.4980624 -2.9708413 0.6754918 -0.9900322
$`2`
[1] -1.0303741 -1.7432638 0.9466315 -1.3322712 -1.7281613 -0.1951453 0.3789493
$`3`
[1] -1.4120119 0.3675425 -0.8378275 -1.1080856 -0.9369994 1.0823376 1.2194782
$`4`
[1] NA NA NA 0.1757164 -1.5768032 0.3121876 0.4443616

Appending list of dates to list of lists removes date format

I'm trying to append a list of dates to a list of lists such as myList below. This is working as expected except the date format for the date element in each list element is lost. Any ideas?
myList<-list(list("event"="A"),
list("event"="B"),
list("event"="C"))
dates<-as.Date(c("2011-06-05","2012-01-12","2016-05-09"))
outList<-mapply(FUN="c",myList,eventDate=as.list(dates),SIMPLIFY = FALSE)
I'm looking to achieve the below
[[1]]
[[1]]$event
[1] "A"
[[1]]$eventDate
[1] "2011-06-05"
[[2]]
[[2]]$event
[1] "B"
[[2]]$eventDate
[1] "2012-01-12"
[[3]]
[[3]]$event
[1] "C"
[[3]]$eventDate
[1] "2016-06-09"
Using Map, you can also create a small (lambda) function like so:
myList <- list(
list(event = "A"),
list(event = "B"),
list(event = "C")
)
dates <- as.Date(c("2011-06-05", "2012-01-12", "2016-05-09"))
outList <- Map(f = function(origList, date) {
origList$eventDate <- date
return(origList)
}, myList, dates)
outList
#> [[1]]
#> [[1]]$event
#> [1] "A"
#>
#> [[1]]$eventDate
#> [1] "2011-06-05"
#>
#>
#> [[2]]
#> [[2]]$event
#> [1] "B"
#>
#> [[2]]$eventDate
#> [1] "2012-01-12"
#>
#>
#> [[3]]
#> [[3]]$event
#> [1] "C"
#>
#> [[3]]$eventDate
#> [1] "2016-05-09"
The reason why you get the dates converted to numbers, is that the c function converts all elements to the lowest common type (usually characters, in this case numeric).
For example:
c(123, as.Date("2016-01-01"))
#> [1] 123 16801
It may be better to index as c could coerce it to integer storage value
for(i in seq_along(myList)) myList[[i]][['eventDate']] <- dates[i]
An additional list wrapper to insulate each Date element will also work here. I constructed that by running an lapply with the list function on the dates vector:
Map("c", myList, eventDate=lapply(dates, list))
[[1]]
[[1]]$event
[1] "A"
[[1]]$eventDate
[1] "2011-06-05"
[[2]]
[[2]]$event
[1] "B"
[[2]]$eventDate
[1] "2012-01-12"
[[3]]
[[3]]$event
[1] "C"
[[3]]$eventDate
[1] "2016-05-09"

replace the objects in one list with respective objects in another list

a is a list. a<-list(1,3,4,2,5,6)
b is also a list. b<-list(c(1,2),4,5,6,7,8)
p is an indicator. p<-c(T,F,T,T,T,T)
If p is true, then we replace a with b at the respective position. Otherwise, just keep a as it was.
So the expected result is as follows:
[[1]]
[1] 1 2
[[2]]
[1] 3
[[3]]
[1] 5
[[4]]
[1] 6
[[5]]
[1] 7
[[6]]
[1] 8
I used the following code to calculate:
replace(a,b,p)
However, it turned out that:
Error in replace(a, b, p) : invalid subscript type 'list'
Could you help with this, thank you!
I think this should work:
a[p]<-b[p]
or:
ifelse(p, b, a)

How do I combine lists of identical lengths into one?

Assuming I have two lists:
xx <- as.list(1:3)
yy <- as.list(LETTERS[1:3])
How do I combine the two such that each element of the new list is a list of the corresponding elements of each component list. So if I combined the two above, I should get:
> combined_list
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] "a"
[[2]]
[[2]][[1]]
[1] 2
[[2]][[2]]
[1] "b"
[[3]]
[[3]][[1]]
[1] 3
[[3]][[2]]
[1] "c"
If you can suggest a solution, I'd like to scale this to 3 or more.
This should do the trick. Nicely, mapply() will take an arbitrary number of lists as arguments.
xx <- as.list(1:3)
yy <- as.list(LETTERS[1:3])
zz <- rnorm(3)
mapply(list, xx, yy, zz, SIMPLIFY=FALSE)

Resources