Appending a List to a List of Lists in R

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



Leave a reply



Submit