Appending a list to a list of lists in R
Could it be this, what you want to have:
# Initial list:
myList <- list()
# Now the new experiments
for(i in 1:3){
myList[[length(myList)+1]] <- list(sample(1:3))
}
myList
How to append to a list from multiple list in r?
You can use mapply
to combine multiple lists into one. The function used within mapply
is c
list4 <- mapply(c, list1, list2, list3, SIMPLIFY = F)
Sample data:
list1 <- as.list(c(1:10))
list2 <- as.list(c(101:110))
list3 <- as.list(c(1001:1010))
Adding elements to a list in R (in nested lists)
It works with append
and list
:
append(l3, list(l4))
The result:
> str(append(l3, list(l4)))
List of 3
$ :List of 5
..$ : num 1
..$ : num 2
..$ : num 3
..$ : num 4
..$ : num 5
$ :List of 5
..$ : num 6
..$ : num 7
..$ : num 8
..$ : num 9
..$ : num 10
$ :List of 5
..$ : num 31
..$ : num 32
..$ : num 33
..$ : num 34
..$ : num 35
Create list of lists in R
Actually you are already close to your desired output, but you may need another list()
within append
, e.g.,
newl <- list()
newl <- append(newl, list(list(a = 1, b = "x")))
newl <- append(newl, list(list(a = 15, b = "y")))
newl <- append(newl, list(list(a = 10, b = "z")))
such that
> newl
[[1]]
[[1]]$a
[1] 1
[[1]]$b
[1] "x"
[[2]]
[[2]]$a
[1] 15
[[2]]$b
[1] "y"
[[3]]
[[3]]$a
[1] 10
[[3]]$b
[1] "z"
If you want to sort by $a
, you can try
> newl[order(sapply(newl, `[[`, "a"))]
[[1]]
[[1]]$a
[1] 1
[[1]]$b
[1] "x"
[[2]]
[[2]]$a
[1] 10
[[2]]$b
[1] "z"
[[3]]
[[3]]$a
[1] 15
[[3]]$b
[1] "y"
appending elements of list to the next element of that list
The problem can be rephrased as to update the current element of the list based on the previous element of the list.
The loop can be simplified to a one-liner:
lol <- list(l1 = list(a = c(1:3), b = c(4:6), c = 2),
l2 = list(a = c(1:3), b = c(4:6)),
l3 = list(a = c(1:3), b = c(4:6)))
foo <- function(x){
sum(x$a, x$b)*x$c
}
for(i in seq_along(lol)[-1]){
lol[[i]][["c"]] <- foo(lol[[i - 1L]])
}
lol
#> $l1
#> $l1$a
#> [1] 1 2 3
#>
#> $l1$b
#> [1] 4 5 6
#>
#> $l1$c
#> [1] 2
#>
#>
#> $l2
#> $l2$a
#> [1] 1 2 3
#>
#> $l2$b
#> [1] 4 5 6
#>
#> $l2$c
#> [1] 42
#>
#>
#> $l3
#> $l3$a
#> [1] 1 2 3
#>
#> $l3$b
#> [1] 4 5 6
#>
#> $l3$c
#> [1] 882
Created on 2022-05-11 by the reprex package (v2.0.1)
Edit
Here is another solution, based on Ritchie Sacramento's comment.
lol <- list(l1 = list(a = c(1:3), b = c(4:6), c = 2),
l2 = list(a = c(1:3), b = c(4:6)),
l3 = list(a = c(1:3), b = c(4:6)))
foo <- function(x, y) {
sum(y$a, y$b)*x
}
newc <- Reduce(foo, lol[-1], init = lol[[1]][["c"]], accumulate = TRUE)
Map(\(x, newc) {x[["c"]] <- newc; x}, lol, newc)
#> $l1
#> $l1$a
#> [1] 1 2 3
#>
#> $l1$b
#> [1] 4 5 6
#>
#> $l1$c
#> [1] 2
#>
#>
#> $l2
#> $l2$a
#> [1] 1 2 3
#>
#> $l2$b
#> [1] 4 5 6
#>
#> $l2$c
#> [1] 42
#>
#>
#> $l3
#> $l3$a
#> [1] 1 2 3
#>
#> $l3$b
#> [1] 4 5 6
#>
#> $l3$c
#> [1] 882
Created on 2022-05-11 by the reprex package (v2.0.1)
Edit 2
To also have newc
in the result any of the following will do.
Note that like above the solutions have different functions foo
. The second one is the function in Ritchie Sacramento's comment, now deleted, that I have reproduced above in the Reduce/Map
solution.
Solution 1, with newc
foo <- function(x){
sum(x$a, x$b)*x$c
}
for(i in seq_along(lol)[-1L]){
lol[[i]][["c"]] <- foo(lol[[i - 1L]])
lol[[i]][["newc"]] <- foo(lol[[i]])
}
lol
Solution 2, with newc
foo <- function(x, y) {
sum(y$a, y$b)*x
}
newc <- Reduce(foo, lol, init = lol[[1]][["c"]], accumulate = TRUE)
Map(\(x, c, newc) {
x[["c"]] <- c
x[["newc"]] <- newc
x
}, lol, newc[-length(newc)], newc[-1])
lol
Rowbind List of lists in R
Here is an approach using rlist
and purr
do.call(rlist::list.zip, out) %>%
purrr::map(~ do.call(rbind, .))
Or, with even more purrr
:
library(purrr)
out %>%
do.call(rlist::list.zip, .) %>%
map(~ reduce(., rbind))
in r combine a list of lists into one list
We can use the concatenate function (c
) within do.call
to flatten the nested list
res <- do.call(c, listoflists)
all.equal(listofvectors, res, check.attributes = FALSE)
#[1] TRUE
Or as @d.b mentioned in the comments, unlist
with recursive = FALSE
can also work
unlist(listoflists, recursive = FALSE)
Haskell - Append to a list inside a list of lists and return the lists of lists updated
let { xs = [[1]] ; y = 2 ; zs = [(xs!!0) ++ [y]] } in zs
is one example to try at the GHCi prompt.
It returns [[1,2]]
.
And for the case of e.g. [[1],[2,3],[4]]
and the like, we can do
appendToFirst :: [[a]] -> a -> [[a]]
appendToFirst (xs:r) y = (xs ++ [y]) : r
so that
> appendToFirst [[1],[2,3],[4]] 0
[[1,0],[2,3],[4]]
The (xs:r)
on the left of the equal sign is a pattern.
The (:)
in the ( (...) : r)
on the right of the equal sign is a "cons
" operation, a data constructor, (:) :: t -> [t] -> [t]
.
xs
is bound to the input list's "head" i.e. its first element, and r
is bound to the rest of the input list, in the pattern; and thus xs
's value is used in creating the updated version of the list, with the first sublist changed by appending a value to its end, and r
remaining as is.
xs ++ [y]
creates a new entity, new list, while xs
and y
continue to refer to the same old values they were defined as. Since Haskell's values and variables are immutable, as you indeed have mentioned.
edit: If you want to add new element at the end of some sublist in the middle, not the first one as shown above, this can be done with e.g. splitAt
function, like
appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y xs =
let
(a,b) = splitAt i xs
in
init a ++ [last a ++ [y]] ++ b
Trying it out:
> appendInTheMiddle 2 0 [[1],[2],[3],[4]]
[[1],[2,0],[3],[4]]
Adding the error-handling, bounds checking, and adjusting the indexing if 0-based one is desired (that one would lead to a simpler and faster code, by the way), is left as an exercise for the reader.
Syntactically, this can be streamlined with "view patterns", as
{-# LANGUAGE ViewPatterns #-}
appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y (splitAt i -> (a,b)) =
init a ++ [last a ++ [y]] ++ b
Applying a loop to a list of lists in r
The problem here is that the data_to_add
is empty. It is empty because listJii[[i]]$Date_record
does not exist. Because a list of lists (i.e., a nested list) can be more confusing than a simple list or a data frame, you need to work through the layers of list structures (from outside in) to find the location of the vector that you seek. The Date_record
in this case is in listJii[[i]][[j]]
.
How to build a nested loop to evaluate a vector in a nested list?
A trick to getting the nested loops correct is to work from the inside out.
Step 1. Make sure the core function works, without using loops.
Test the command line(s) with sample vectors in the nested list.
unique(listJii[[1]][[1]]$Date_record) # this is what you want to store in `data_to_add`
# you have two layers of lists in `listJii`, so you need two list layers in `data_to_add`
data_to_add <- list()
data_to_add[[1]] <- list()
data_to_add[[1]][[1]] <- unique(listJii[[1]][[1]]$Date_record)
# test
data_to_add # you needed all those commands above to make this work, so those will be necessary in your function
Step 2. Build your loops, one at a time, first by replacing the innermost variable that needs changing and then work your way out. Test it every step along the way.
## innermost loop test
data_to_add <- list()
data_to_add[[1]] <- list()
for(j in seq_along(listJii[[1]])) {
data_to_add[[1]][[j]] <- unique(listJii[[1]][[j]]$Date_record)
}
# test
data_to_add # the innermost loop works
## outer loop test
data_to_add <- list()
for(i in seq_along(listJii)) {
data_to_add[[i]] <- list()
for(j in seq_along(listJii[[i]])) {
data_to_add[[i]][[j]] <- unique(listJii[[i]][[j]]$Date_record)
}
}
# test
data_to_add # the final loop works--this function is now ready
Your listJsubs
function works with the data_to_add
built here. Though, because nested lists are used in your evaluation, you may want to consider using nested loops to follow through for listJsubs
as well.
An alternative to using nested loops on nested lists is using nested lapply()
lapply()
is another function that you can use instead of for-loops over a list.
Its output is a list, so you do not need to assign empty list structures beforehand to data_to_add
and data_to_add[[i]]
like the way you need for for-loops.
data_to_add <- lapply(listJii, function(i){
lapply(i, function(j){
return(unique(j$Date_record))
})
})
Note: the core function in this nested lapply()
is a bit different from the one used in the nested for-loops. It's a different approach that I could do with lapply()
and get the same results. I actually built it from outside in--hence, you don't see any i
in the core function.
append a list element-wise to elements of a nested list in R
You can use Map
which does exactly what mapply(..., simplify = F)
do:
Map(c, lst1, lst2)
[[1]]
[1] "ABC" "DEF" "GHI" "abc"
[[2]]
[1] "JKL" "MNO" "PQR" "def"
Related Topics
Merge Dataframes, Different Lengths
Group Data and Plot Multiple Lines
How to Embed an Image in a Cell a Table Using Dt, R and Shiny
Compute Monthly Averages from Daily Data
R: Ggplot Stacked Bar Chart with Counts on Y Axis But Percentage as Label
Equivalent to Rowmeans() for Min()
How Achieve Identical Facet Sizes and Scales in Several Multi-Facet Ggplot2 Graphics
Add Image in Title Page of Rmarkdown PDF
Add Values to a Reactive Table in Shiny
Creating (And Accessing) a Sparse Matrix with Na Default Entries
Check If a Date Is Within an Interval in R
How to Get the Number of Rows in a CSV File Without Opening It
Saving and Loading a Model in R
Rselenium: Server Signals Port Is Already in Use
Create New Column Based on 4 Values in Another Column
R Command Line Passing a Filename to Script in Arguments (Windows)