PhDavey
PhDavey

Reputation: 416

lapply alternative to return list of different length than input

I've been using lapply a little bit to work with lists, however I can't figure out how exactly to figure out how to return the result I want.

I have a small subset of my data (I had to remove the '<'environment'>' from the dput, so it looks a little weird)

example <- list(structure(c(E10 = 1L, E82 = 2L, D81 = 4L, E04 = 12L, E06 = 15L
), class = "igraph.vs", graph = "9eef1560-da23-11ed-9a93-8f4ed5a9da01"), 
structure(c(E10 = 1L, E82 = 2L, D81 = 4L, E04 = 12L, E09 = 16L
), class = "igraph.vs", graph = "9eef1560-da23-11ed-9a93-8f4ed5a9da01"), 
structure(c(E10 = 1L, E82 = 2L, D44 = 10L, E05 = 5L, A84 = 14L
), class = "igraph.vs", graph = "9eef1560-da23-11ed-9a93-8f4ed5a9da01"))
[[1]]
+ 5/? vertices, named, from 9eef156 (deleted):
[1] E10 E82 D81 E04 E06

[[2]]
+ 5/? vertices, named, from 9eef156 (deleted):
[1] E10 E82 D81 E04 E09

[[3]]
+ 5/? vertices, named, from 9eef156 (deleted):
[1] E10 E82 D44 E05 A84

My goal was to loop through each element in the list, and return 3 lists. From, To, and Group. The group is the first label in a list, in this initial case E10, then the from and to are just pairwise moving through the labels, so E10 and E82, then E82 and D81 and so on. I've kind of approximated what I want to achieve using the following code. Note: the traj_length is a variable of value 5 in this instance, will change from use to use.

output <- lapply(example, function(x) list(from = attributes(x)$names[1:(traj_length-1)], to = attributes(x)$names[2:(traj_length)], group = rep(attributes(x)$names[1], traj_length-1)))
> output
[[1]]
[[1]]$from
[1] "E10" "E82" "D81" "E04"

[[1]]$to
[1] "E82" "D81" "E04" "E06"

[[1]]$group
[1] "E10" "E10" "E10" "E10"


[[2]]
[[2]]$from
[1] "E10" "E82" "D81" "E04"

[[2]]$to
[1] "E82" "D81" "E04" "E09"

[[2]]$group
[1] "E10" "E10" "E10" "E10"


[[3]]
[[3]]$from
[1] "E10" "E82" "D44" "E05"

[[3]]$to
[1] "E82" "D44" "E05" "A84"

[[3]]$group
[1] "E10" "E10" "E10" "E10"

Which is close, but instead of a list for each element (1,2,3 etc) I want to return 3 lists, with each value there, and the values separated out so I can easily convert into a dataframe. Looking something like this:

$from[[1]]
"E10"

$to[[1]]
"E82"

$group[[1]]
"E10"

$from[[2]]
"E82"

$to[[2]]
"D81"

$group[[2]]
"E10"

Any suggestions or advice would be appreciated!

Edit:

To respond to thus__' comment; We have a list of pairs that have been selected based on the counts for each pair in our dataset. We are aiming to assemble all the simple paths of a specified length (in this case 5) with each potential start node. I've already created a list of all simple paths in the data, filtered for the ones that are length 5. Now just reassembling them and assigning a group for each one before plotting or applying LCS (Longest Common Subsequence) score to them to filter for the most frequent paths.

Upvotes: 0

Views: 53

Answers (2)

Dan Adams
Dan Adams

Reputation: 5254

This is exactly what purrr::list_transpose() does.

library(purrr)

list_transpose(l)
#> $from
#> $from[[1]]
#> [1] "E10" "E82" "D81" "E04"
#> 
#> $from[[2]]
#> [1] "E10" "E82" "D81" "E04"
#> 
#> $from[[3]]
#> [1] "E10" "E82" "D44" "E05"
#> 
#> 
#> $to
#> $to[[1]]
#> [1] "E82" "D81" "E04" "E06"
#> 
#> $to[[2]]
#> [1] "E82" "D81" "E04" "E09"
#> 
#> $to[[3]]
#> [1] "E82" "D44" "E05" "A84"
#> 
#> 
#> $group
#> $group[[1]]
#> [1] "E10" "E10" "E10" "E10"
#> 
#> $group[[2]]
#> [1] "E10" "E10" "E10" "E10"
#> 
#> $group[[3]]
#> [1] "E10" "E10" "E10" "E10"

DATA:

l <- list(
  list(
    from = c("E10", "E82", "D81", "E04"),
    to = c("E82", "D81", "E04", "E06"),
    group = c("E10", "E10", "E10", "E10")
  ),
  list(
    from = c("E10", "E82", "D81", "E04"),
    to = c("E82", "D81", "E04", "E09"),
    group = c("E10", "E10", "E10", "E10")
  ),
  list(
    from = c("E10", "E82", "D44", "E05"),
    to = c("E82", "D44", "E05", "A84"),
    group = c("E10", "E10", "E10", "E10")
  )
)

Upvotes: 0

Onyambu
Onyambu

Reputation: 79318

In base R you could do:

fn2<- function(x){
    y <- names(x)
    z <- data.frame(from = head(y, -1), to = y[-1], group=y[1])
    lapply(asplit(z, 1), as.list)
  }
lapply(example, fn2)

You can also use transpose from purrr as shown below:

fn <- function(x){
   y <- names(x)
   data.frame(from = head(y, -1), to = y[-1], group=y[1])
 }
library(purrr)
map(example, ~ transpose(fn(.x)))


[[1]]
[[1]][[1]]
[[1]][[1]]$from
[1] "E10"

[[1]][[1]]$to
[1] "E82"

[[1]][[1]]$group
[1] "E10"


[[1]][[2]]
[[1]][[2]]$from
[1] "E82"

[[1]][[2]]$to
[1] "D81"

[[1]][[2]]$group
[1] "E10"


[[1]][[3]]
[[1]][[3]]$from
[1] "D81"

[[1]][[3]]$to
[1] "E04"

[[1]][[3]]$group
[1] "E10"

Upvotes: 0

Related Questions