Rename elements of list based on condition

Viewed 175

I have a huge list samplelist containing various tibbles (in the simplified sample called Alpha, Beta and Gamma). Each tibble contains various elements (in the sample called sample_0 and sample_1). However, not each tibble contains each element (Gamma contains only sample_0, but not sample_1). What I would like to do is to rename the elements based on a condition: if there is an element sample_1 in a tibble, rename it to sampling. However, if the tibble does not contain sample_1, rename sample_0 to sampling (so that the list now contains an element called sampling for each tibble).

samplelist <- list(Alpha = structure(list(sample_0 = c(3, NA, 7, 9, 2),
                                     sample_1 = c(NA, 8, 5, 4, NA)),
                                row.names = c(NA, -5L),
                                class = c("tbl_df", "tbl", "data.frame")),
              Beta = structure (list(sample_0 = c(2, 9, NA, 3, 7),
                                     sample_1 = c(3, 7, 9, 3, NA)),
                                row.names = c(NA, -5L),
                                class = c("tbl_df", "tbl", "data.frame")),
              Gamma = structure(list(sample_0 = c(NA, NA, 4, 6, 3)),
                                row.names = c(NA, -5L),
                                class = c("tbl_df", "tbl", "data.frame")))

Does anybody know how to get the following desired output?

samplelist
$Alpha
# A tibble: 5 x 2
  sample_0 sampling
     <dbl>    <dbl>
1        3       NA
2       NA        8
3        7        5
4        9        4
5        2       NA

$Beta
# A tibble: 5 x 2
  sample_0 sampling
     <dbl>    <dbl>
1        2        3
2        9        7
3       NA        9
4        3        3
5        7       NA

$Gamma
# A tibble: 5 x 1
       sampling
          <dbl>
  1          NA
  2          NA
  3           4
  4           6
  5           3

EDIT With the code provided by @akrun:

map(errorlist,  ~  if(ncol(.x) == 1 && names(.x) == 'sample_0')
      setNames(.x, 'sampling') else 
      rename_with(.x, ~ 'sampling', matches('sample_1')))

I got the disired output for my samplelist. However, if there's more than one group in Gamma, the (adjusted) code only works for Alpha and Beta, yet leaves Gamma unchanged (Delta added from before editing):

errorlist <- list(Alpha = structure(list(sample_0 = c(3, NA, 7, 9, 2),
                                         sample_1 = c(NA, 8, 5, 4, NA),
                                         sample_2 = c(7, 3, 5, NA, NA)),
                                    row.names = c(NA, -5L),
                                    class = c("tbl_df", "tbl", "data.frame")),
                  Beta = structure (list(sample_0 = c(2, 9, NA, 3, 7),
                                         sample_1 = c(3, 7, 9, 3, NA),
                                         sample_2 = c(4, 2, 6, 4, 6)),
                                    row.names = c(NA, -5L),
                                    class = c("tbl_df", "tbl", "data.frame")),
                  Gamma = structure(list(sample_0 = c(NA, NA, 4, 6, 3),
                                         sample_1 = c(3, 7, 3, NA, 8)),
                                    row.names = c(NA, -5L),
                                    class = c("tbl_df", "tbl", "data.frame")),
                  Delta = structure (list(error = c(3, 7, 9, 3, NA)),
                                     row.names = c(NA, -5L),
                                     class = c("tbl_df", "tbl", "data.frame")))

map(errorlist,  ~  if(ncol(.x) == 1 && names(.x) == 'sample_1')
  setNames(.x, 'sampling') else 
    rename_with(.x, ~ 'sampling', matches('sample_2')))

Output:

$Alpha
# A tibble: 5 x 3
  sample_0 sample_1 sampling
     <dbl>    <dbl>    <dbl>
1        3       NA        7
2       NA        8        3
3        7        5        5
4        9        4       NA
5        2       NA       NA

$Beta
# A tibble: 5 x 3
  sample_0 sample_1 sampling
     <dbl>    <dbl>    <dbl>
1        2        3        4
2        9        7        2
3       NA        9        6
4        3        3        4
5        7       NA        6

$Gamma
# A tibble: 5 x 2
  sample_0 sample_1
     <dbl>    <dbl>
1       NA        3
2       NA        7
3        4        3
4        6       NA
5        3        8

$Delta
# A tibble: 5 x 1
  error
  <dbl>
1     3
2     7
3     9
4     3
5    NA
1 Answers

Here is an option - loop over the list with map and do the changes with a condition (if/else) (Here, we are using errorlist as it is more general. It also works with samplelist)

library(dplyr)
library(purrr)
map(errorlist,  ~  if(ncol(.x) == 1 && names(.x) == 'sample_0')
      setNames(.x, 'sampling') else 
      rename_with(.x, ~ 'sampling', matches('sample_1')))

-output

$Alpha
# A tibble: 5 × 2
  sample_0 sampling
     <dbl>    <dbl>
1        3       NA
2       NA        8
3        7        5
4        9        4
5        2       NA

$Beta
# A tibble: 5 × 2
  sample_0 sampling
     <dbl>    <dbl>
1        2        3
2        9        7
3       NA        9
4        3        3
5        7       NA

$Gamma
# A tibble: 5 × 1
  sampling
     <dbl>
1       NA
2       NA
3        4
4        6
5        3

$Delta
# A tibble: 5 × 1
  error
  <dbl>
1     3
2     7
3     9
4     3
5    NA

Update

Based on the OP's comments

lapply(errorlist, \(x) {
  nm1 <- stringr::str_subset(names(x), "^sample_\\d+$")
  i1 <- which.max(as.numeric(stringr::str_extract(nm1, 
       "(?<=sample_)\\d+")))
   if(length(i1) > 0) names(x)[names(x) == nm1[i1]] <- "sampling"
   x})

-output

$Alpha
# A tibble: 5 × 3
  sample_0 sample_1 sampling
     <dbl>    <dbl>    <dbl>
1        3       NA        7
2       NA        8        3
3        7        5        5
4        9        4       NA
5        2       NA       NA

$Beta
# A tibble: 5 × 3
  sample_0 sample_1 sampling
     <dbl>    <dbl>    <dbl>
1        2        3        4
2        9        7        2
3       NA        9        6
4        3        3        4
5        7       NA        6

$Gamma
# A tibble: 5 × 2
  sample_0 sampling
     <dbl>    <dbl>
1       NA        3
2       NA        7
3        4        3
4        6       NA
5        3        8

$Delta
# A tibble: 5 × 1
  error
  <dbl>
1     3
2     7
3     9
4     3
5    NA
Related