1

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
Gnueghoidune
  • 1,237
  • 4
  • 13

1 Answers1

0

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
akrun
  • 874,273
  • 37
  • 540
  • 662
  • For the example, it worked like a charm, thank you! However, if I add another element "sample_2" for Alpha and Beta and "sample_1" for Gamma (and accordingly update the statements in your loop to ... map(errorlist, ~ if(ncol(.x) == 1 && names(.x) == 'sample_1') setNames(.x, 'sampling') else rename_with(.x, ~ 'sampling', matches('sample_2'))) ..., it only changes sample_2 to sampling, yet sample_1 remains unchanged. Could this be to the statement ... if(ncol(.x) == 1 ..., which does not hold true anymore? Furthermore, could you explain why you used setNames first, and then rename_with? – Gnueghoidune Feb 11 '22 at 09:49
  • @Gnueghoidune because there was only a single column and it was much more easier to use `setNames` . Your comment about the new issue is not clear to me – akrun Feb 11 '22 at 15:30
  • Edited the question to clarify the new issue – Gnueghoidune Feb 14 '22 at 10:59
  • @Gnueghoidune try the update – akrun Feb 14 '22 at 17:13
  • 1
    After having changed the backslash in the first row to function, it worked impeccably! You are a real hero! – Gnueghoidune Feb 14 '22 at 18:12
  • @Gnueghoidune i think that may be because your R version is old. It is a shortcut for lambda function (`function(x)`) – akrun Feb 14 '22 at 18:13