aspeddro
aspeddro

Reputation: 87

R dynamically merge multiple columns with NA into a single column

Is there a way to dynamically merge columns with NA values?

tibble(
  x = c(1:2, NA, NA, NA, NA, NA),
  y = c(NA, NA, 4:7, NA),
  z = c(NA, NA, NA, NA, NA, NA, 9)
)

# A tibble: 7 x 3
      x     y     z
  <int> <int> <dbl>
1     1    NA    NA
2     2    NA    NA
3    NA     4    NA
4    NA     5    NA
5    NA     6    NA
6    NA     7    NA
7    NA    NA     9

expect:

# A tibble: 7 x 3
      x     y     z
  <int> <int> <dbl>
1     1    NA    NA
2     2    NA    NA
3     4     4    NA
4     5     5    NA
5     6     6    NA
6     7     7    NA
7     9    NA     9

This example is a read from an xlsx file, so in some cases the column yor z may not exist

Upvotes: 2

Views: 384

Answers (2)

TarJae
TarJae

Reputation: 79246

Update With the help of Ronak. See comments: Now it should work for df with different columns: More general solution for coalesce in combination with do.call

library(dplyr)
df <- tibble(
  x = c(1:2, NA, NA, NA, NA, NA),
  y = c(NA, NA, 4:7, NA)
)

df %>%
  mutate(result = do.call(coalesce, df))

Output:

      x     y result
  <int> <int>  <int>
1     1    NA      1
2     2    NA      2
3    NA     4      4
4    NA     5      5
5    NA     6      6
6    NA     7      7
7    NA    NA     NA

First answer This is a job for coalesce from dplyr package: finds the first non-missing value at each position.

library(dplyr)
df %>% mutate(result = coalesce(x,y,z))

Output:

      x     y     z result
  <int> <int> <dbl>  <dbl>
1     1    NA    NA      1
2     2    NA    NA      2
3    NA     4    NA      4
4    NA     5    NA      5
5    NA     6    NA      6
6    NA     7    NA      7
7    NA    NA     9      9

Upvotes: 3

Ronak Shah
Ronak Shah

Reputation: 389275

You can get the first non-NA value from each row :

library(dplyr)

df %>%
  rowwise() %>%
  mutate(result = na.omit(c_across())[1]) %>%
  ungroup

#      x     y     z result
#  <int> <int> <dbl>  <dbl>
#1     1    NA    NA      1
#2     2    NA    NA      2
#3    NA     4    NA      4
#4    NA     5    NA      5
#5    NA     6    NA      6
#6    NA     7    NA      7
#7    NA    NA     9      9

In base R :

df$result <- apply(df, 1, function(x) na.omit(x)[1])

Upvotes: 2

Related Questions