Соберите все строки с отступом в списке - PullRequest
0 голосов
/ 18 октября 2018

У меня есть текстовый файл в следующем формате

Information I want:
    info1 a
    info2 b
    info3 c
More information I want:
    info1 1 
    info2 2
    info3 3

Я хочу проанализировать этот файл в R так, чтобы все строки с отступами были в пределах одного и того же именованного вектора в списке.

т.е.Чтобы результаты выглядели следующим образом

list(infoIwant = list(info1 = "a", info2 = "b", info3 = "c"),
 otherinfo = list(info1 = "1", info2 = "2", info3 = "3"))

У кого-нибудь есть какие-либо рекомендации, как это сделать?Единственный способ, которым я могу придумать, - это включить несколько операторов if, зависящих от начала строки, но также поддерживая предыдущую строку, и кажется, что все довольно быстро усложняется, так что ищите помощи!

1 Ответ

0 голосов
/ 18 октября 2018

Я бы сделал это с парой tidyverse функций.Возможно, имеет смысл поместить данные в простой текстовый файл - мне просто нужно было использовать его как строку для использования с reprex здесь.

База readLines ожидает файл или другое соединение,но readr::read_lines позволяет читать в строке.Опять же, может быть, это не имеет значения на практике.Считав это, вы получите один вектор, по одной записи на строку в файле.

library(tidyverse)

text <- "Information I want:
    info1 a
    info2 b
    info3 c
More information I want:
    info1 1 
    info2 2
    info3 3
"

read_lines(text)
#> [1] "Information I want:"      "    info1 a"             
#> [3] "    info2 b"              "    info3 c"             
#> [5] "More information I want:" "    info1 1 "            
#> [7] "    info2 2"              "    info3 3"

Преобразуйте его во фрейм данных - я использовал as_tibble, который затем дает мне столбец value этоговектор.Затем я делю его на 2 столбца, разделяя их регулярным выражением \\s{2,}, то есть делим там, где есть 2 или более последовательных пробела.Это превращает пустые области в их собственные записи в первом столбце.

read_lines(text) %>%
  as_tibble() %>%
  separate(value, into = c("header", "info"), sep = "\\s{2,}")
#> # A tibble: 8 x 2
#>   header                   info      
#>   <chr>                    <chr>     
#> 1 Information I want:      <NA>      
#> 2 ""                       info1 a   
#> 3 ""                       info2 b   
#> 4 ""                       info3 c   
#> 5 More information I want: <NA>      
#> 6 ""                       "info1 1 "
#> 7 ""                       info2 2   
#> 8 ""                       info3 3

Но эти пробелы не так полезны для работы.Преобразуйте пробелы в NA, чтобы вы могли использовать tidyr::fill для заполнения любых NA в столбце заголовка любым значением, отличным от NA, до него.Фильтр для удаления NA s в информационном столбце - это места, в которых только заголовок, но нет информации, и обрезка пустых мест, оставшихся в info.

read_lines(text) %>%
  as_tibble() %>%
  separate(value, into = c("header", "info"), sep = "\\s{2,}") %>%
  mutate(header = na_if(header, "")) %>%
  fill(header) %>%
  filter(!is.na(info)) %>%
  mutate(info = str_trim(info))
#> # A tibble: 6 x 2
#>   header                   info   
#>   <chr>                    <chr>  
#> 1 Information I want:      info1 a
#> 2 Information I want:      info2 b
#> 3 Information I want:      info3 c
#> 4 More information I want: info1 1
#> 5 More information I want: info2 2
#> 6 More information I want: info3 3

Наконец, чтобы получитьименованный список из этого фрейма данных, вы можете разделить фрейм данных на header.Это дает вам список из двух фреймов данных.Если вы отобразите этот список и вызовете dplyr::pull, вы можете получить только столбец info в качестве вектора для каждой записи списка.

read_lines(text) %>%
  as_tibble() %>%
  separate(value, into = c("header", "info"), sep = "\\s{2,}") %>%
  mutate(header = na_if(header, "")) %>%
  fill(header) %>%
  filter(!is.na(info)) %>%
  mutate(info = str_trim(info)) %>%
  split(.$header) %>%
  map(pull, info)
#> $`Information I want:`
#> [1] "info1 a" "info2 b" "info3 c"
#> 
#> $`More information I want:`
#> [1] "info1 1" "info2 2" "info3 3"

Создан 2018-10-18 с помощью Представить пакет (v0.2.1)

...