Meagan
Meagan

Reputation: 41

How to extract elements and their indices from a list in R

I would like to extract list elements and their indices in R while removing items with 0 length. Let's say I have the following list in R:

l1 <- character(0)
l2 <- c("a","b")
l3 <- c("c","d","e")
list1 <- list(l1, l1, l2, l1, l3)

Then list1 returns the following:

[[1]]
character(0)
[[2]]
character(0)
[[3]]
[1] "a" "b"
[[4]]
character(0)
[[5]]
[1] "c" "d" "e"

I would like to somehow extract an object that displays the index/position for each non-empty element, as well as the contents of that element. So something that looks like this:

[[3]]
[1] "a" "b"
[[5]]
[1] "c" "d" "e"

The closest I've come to doing this is by removing the empty elements, but then I lose the original index/position of the remaining elements:

list2 <- list1[lapply(list1, length) > 0]
list2
[[1]]
[1] "a" "b"
[[2]]
[1] "c" "d" "e"

Upvotes: 4

Views: 7828

Answers (4)

Dimitrios Zacharatos
Dimitrios Zacharatos

Reputation: 850

A very simple solution is to provide names to the elements of your list and then run your function again. There are several ways to name your elements.

l1 <- character(0)
l2 <- c("a","b")
l3 <- c("c","d","e")
list1 <- list(e1=l1, e2=l1, e3=l2, e4=l1, e5=l3)
list1
names(list1)<-paste0("element",seq(length(list1)))
list1[lapply(list1, length) > 0]

Upvotes: 0

moodymudskipper
moodymudskipper

Reputation: 47300

I'm not sure exactly what 'extract an object that displays' means, but if you just want to print you can use this modified print.

I just slightly edited print.listof (it's not recursive! zero length subelements will be displayed):

print2 <- function (x, ...) 
{
  nn <- names(x)
  ll <- length(x)
  if (length(nn) != ll) 
    nn <- paste0("[[", seq.int(ll),"]]")
  for (i in seq_len(ll)[lengths(x)>0]) {
    cat(nn[i], "\n")
    print(x[[i]], ...)
    cat("\n")
  }
  invisible(x)
}

print2(list1)

[[3]] 
[1] "a" "b"

[[5]] 
[1] "c" "d" "e"

Upvotes: 0

Cristian E. Nuno
Cristian E. Nuno

Reputation: 2920

Overview

Keeping the indices required me to name each element in the list. This answer uses which() to set the condition that I apply to list1 to keep non-zero length elements.

# load data
l1 <- character(0)
l2 <- c("a","b")
l3 <- c("c","d","e")
list1 <- list( l1, l1, l2, l1, l3)

# name each element in the list
names( list1 ) <- as.character( 1:length( list1 ) )

# create a condition that 
# keeps only non zero length elements
# from list1
non.zero.length.elements <-
  which( lapply( X = list1, FUN = length ) != 0 )

# apply the condition to list1
# to view the non zero length elements
list1[ non.zero.length.elements ]
# $`3`
# [1] "a" "b"
# 
# $`5`
# [1] "c" "d" "e"

# end of script #

Upvotes: 0

Paul
Paul

Reputation: 9087

keep, will keep elements matching a predicate. negate(is_empty) creates a function that returns TRUE if a vector is not empty.

library("purrr")


names(list1) <- seq_along(list1)
keep(list1, negate(is_empty))
#> $`3`
#> [1] "a" "b"
#> 
#> $`5`
#> [1] "c" "d" "e"

Upvotes: 5

Related Questions