Get index and value of non-NA list element

Viewed 433

Take a list like as.list(rep(c(NA, 4, NA), times = c(5, 1, 2))) i.e.

[[1]]
[1] NA

[[2]]
[1] NA

[[3]]
[1] NA

[[4]]
[1] NA

[[5]]
[1] NA

[[6]] # index of non-NA list element, 6
[1] 4 # ...and its corresponding value, 4 

[[7]]
[1] NA

[[8]]
[1] NA

I want to extract the index of the non-NA element (here: 6), and its corresponding value (here: 4). Is there any idiomatic way to get these two numbers?

4 Answers

1) Base R Assuming that the list L contains only scalars and NA's this returns a 2 column matrix with one row for each set of xy coordinates and an attribute recording which positions were omitted.

Omit the x= and y= if you don't want the column names. If you don't want the attribute recording the positions of the NA's append [,] to the end of the line. If you know that there is only one scalar you might want to wrap it in c(...) to produce a 2 element vector. If you prefer data frame output replace cbind with data.frame.

na.omit(cbind(x = seq_along(L), y = unlist(L)))

2) tidyverse or using the tidyverse

library(tibble)
library(tidyr)

drop_na(enframe(unlist(L)))

2a) which could alternately be written using pipes like this:

L %>% unlist %>% enframe %>% drop_na

I am not sure this is elegant enough but works;

mylist <- as.list(rep(c(NA, 4, NA), times = c(5, 1, 2)))

x <- (1:length(mylist))[!sapply(mylist,is.na)]
y <- mylist[[x]]

coor <- c(x,y)

coor

output;

6 4
  1. Find index of non NA list == 6 to get x
  2. Remove all list elements with NA to get y
my_list <- as.list(rep(c(NA, 4, NA), times = c(5, 1, 2)))


x <- which(!is.na(my_list))
y <- unlist(Filter(function(a) any(!is.na(a)), my_list))
coordinate <- c(x,y)
coordinate
> coordinate
[1] 6 4

Using stack

na.omit(stack(setNames(L, seq_along(L))))
  values ind
6      4   6
Related