функция: разделение строк, дублирование строк и замена исходной строки разделенными - PullRequest
0 голосов
/ 05 августа 2020

Я впервые пытаюсь кодировать функцию. Предполагается, что строка разбивается на несколько частей и каждая часть возвращается в виде строки таблицы.

Например, допустим, у меня есть такие данные.

nasty_entry <- tibble(ID = 1:3, Var = c("ABC", "AB", "A"))

Я хотел бы получить это.

nice_entry <- tibble(ID = c(1, 1, 1, 2, 2, 3), var = c("A", "B", "C", "A", "B", "A"))

Итак, я пытаюсь закодировать функцию, используя разные типы циклов (для практики), потому что мои исходные данные содержат около 300 записей.

nice_entry <- function(data, var, pattern)
  
  #--------------------DECLARATION--------------------#   
  
  # data : The tibble containing the data to split.
  # var : The variable containing the data to split.
  # pattern : The pattern to use for the spliting.
  
  if(!require(tidyverse)){install.packages("tidyverse")}
  library(tidyverse)
  if(!require(magrittr)){install.packages("tidyverse")}
  library(magrittr)
  
  c1 <- 0 # Reset the counter #1
  c2 <- 0 # Reset the counter #2
  unchanged_rows <- 0 # The number of rows that has been unchanged.
  changed_rows <- 0 # The number of rows that has been changed.
  new_data <- tibble() # The tibble where the data will be stored.
  
  repeat{
    c1 <- c1 +1 # Increase the counter #1 by one at each loop.
    c2 <- 0 # Reset the counter #2 at each loop.

    # Split the string into several strings.
    splited_str <- str_split(string = data %>% select({{ var }}) %>% slice(c1), pattern = pattern) %>% 
                   unlist()
    
    # Add the row into the "new_data" variable if the original string hasn't been splited.
    if(length(splited_str) <= 1) {
      unchanged_rows <- unchanged_rows +1
      new_data <- new_data %>% 
                  bind_rows(slice(data, c1))
      next
    }
    
    # Duplicate the row of the original string. It duplicates it several times according to the 
    # number of times the original string has been splited.
    if(length(splited_str) > 1){
      changed_rows <- changed_rows +1
      duplicated_rows <- data %>% 
                         slice(rep(c1, each = length(splited_str)))
    
      # Replace each original string with the new splited strings.
      while (c2 < length(splited_str)) {
        c2 <- c2 +1
        duplicated_rows <- duplicated_rows %>% 
                           mutate({{ var }} = replace(x = {{ var }}, list = c2, values = splited_str[c2]))
        new_data <- new_data %>% 
                    bind_rows(slice(duplicated_rows, c2))
      }
    }
    
    # Break the loop if the entire tibble has been analyse and return the "new_data" variable.
    if(c1 == length(nrow(data))) {
      break
      return(new_data)
    }
  }
}

Я пробовал то же самое код, используя «реальные переменные» внутри циклов, и, похоже, он работает. Проблема возникает, когда я включаю их в функцию. Я получаю эту ошибку.

Ошибка: объект 'c1' не найден

} Ошибка: неожиданно '}' в "}"

} Ошибка: неожиданно '}' в "}"

Что я делаю не так? Может быть, это проблема с индексированием?.

Я также хотел бы получить несколько советов по функциям кодирования и есть ли альтернативы, чтобы сделать то же самое.

Большое спасибо!

Матье

Ответы [ 2 ]

0 голосов
/ 05 августа 2020

Вот еще один подход, который вы можете захотеть получить

library(tidyverse)
nasty_entry2 <- nasty_entry %>% 
  mutate(Var = strsplit(as.character(Var), "")) %>%
  tidyr::unnest(Var)

# A tibble: 6 x 2
#      ID Var  
#   <int> <chr>
# 1     1 A    
# 2     1 B    
# 3     1 C    
# 4     2 A    
# 5     2 B    
# 6     3 A  
0 голосов
/ 05 августа 2020

Мы можем использовать separate_rows. Задайте поиск по регулярному выражению для соответствия между двумя символами. . в регулярном выражении соответствует любому символу. Итак, это в основном разделение между двумя соседними символами

library(dplyr)
library(tidyr)
nasty_entry %>% 
    separate_rows(Var, sep="(?<=.)(?=.)")
# A tibble: 6 x 2
#     ID Var  
#  <int> <chr>
#1     1 A    
#2     1 B    
#3     1 C    
#4     2 A    
#5     2 B    
#6     3 A    
...