0

Apologies in advance for how tricky this will be to describe and difficult to reproduce with examples, and thanks in advance for reading through!

I am trying to conditionally populate an empty dataframe using a custom function that can return either a single value or multiple values. Each value must be a row in the dataframe. The multiple values come from the fact that nested lists are passed to the function, some of which have just 1 list, some of which have 9 or 10 sub-lists.

Normally, a simple for loop with indexing would do:

for (i in 1:nrow(df)){
    df[i,] <- function(x[i])
}

But because my function can return multiple values, each of which must be a row, the index is constantly changing and I can't figure out how to update it. Essentially what I've been trying is:

for (i in 1:nrow(df)){    # where df is the empty df I want to fill
df[i,] <- if(another.corresponding.df == 1){function(x[i])    # if there is only 1 nested list at index i, apply the function and write the returned value to the corresponding row
  } else {
       for (j in 1:another.corresponding.df[i]){   # if there are multiple nested lists at index i, loop through j nested lists
          if(j == 1) {df[i,] <- function(x[i][j])  # use index 1 as the row
           } else { df[i+1,] <- function(x[i][j])  # update the row number based on however many j nested lists produced values
      }
  }
}

^ This works until the first multiple-value index is encountered, after which the original index is thrown off and I receive the following: Error in x[[jj]][iseq] <- vjj : replacement has length zero

For example, say I'm using list x to construct my dataframe, where x is a list of 3 sub-lists: x[1] has 1 value, x[2] has 2 values and x[3] has 1 value:

x <- list(2:7, list(12:15, 15:17), 10:14)

x
[[1]]
[1] 2 3 4 5 6 7

[[2]]
[[2]][[1]]
[1] 12 13 14 15

[[2]][[2]]
[1] 15 16 17

[[3]]
[1] 10 11 12 13 14

I want to apply my function to all elements of this list to populate my dataframe such that it has 4 rows total, where

row 1 = function(x[1])
row 2 = function(x[2][1]) 
row 3 = function(x[2][2])
row 4 = function(x[3])

Thus, once I apply the df[i+1,] portion of my code above, row 3 is filled in with the values of x[2][2], so I cannot use i = 3 to get at x[3].

I need to iteratively update the index value based on however many nested lists I run through -- how can I do this?

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
GeoCat333
  • 69
  • 2
  • 8
  • It looks like you want to flatten the list first and then iterate your function of it. See this answer: https://stackoverflow.com/a/41882883/8675075 for how to do this with nested lists. – Paul Dec 02 '19 at 01:15

1 Answers1

1

Assuming the function to apply to each list is fun1 and the list we have is called lst1 we can try something like this

apply_fun <- function(x) {
   if (is.list(x)) 
     do.call(rbind, lapply(x, fun1))
   else fun1(x)
}

do.call(rbind, lapply(lst1, apply_fun))

apply_fun checks if it's a nested list and applies fun1 to each element of the nested list.

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213