Вставьте или замените несколько совпадений одной и той же строки бегущим счетчиком - PullRequest
0 голосов
/ 20 февраля 2020

У меня есть RIS (текстовый) файл, который выглядит примерно так:

mylist <- c("TI  - a", "AU  - b", "ER  -", " ",
          "TI  - c", "AU  - d", "ER  -", " ",
          "TI  - e", "AU  - f", "ER  -")

Я бы хотел вставить тег работающего идентификатора следующим образом

mylist_with_ids <- c("TI  - a", "AU  - b", "ID  - 1", "ER  -", " ",
                   "TI  - c", "AU  - d", "ID  - 2", "ER  -", " ",
                   "TI  - e", "AU  - f", "ID  - 3", "ER  -")

Мой оригинальный подход был написать stringr::str_replace l oop, где я заранее сгенерирую список ID.

cc_id_replace <- paste0("ID  - ", 1:3, "\nER  -")
for (i in 1:3) {
  mylist_with_ids <- str_replace(mylist, "^ER  -", cc_id_replace[i])
}

Конечно, это не работает по нескольким причинам. Что может быть лучше? (Существует много вопросов о регулярных выражениях и множественных массивах, но я так и не смог найти ответ.)

Ответы [ 3 ]

0 голосов
/ 20 февраля 2020

Я думаю, что здесь можно использовать кодирование длин серий.

(Кстати: мне не нравится использовать list в качестве имени переменной, поскольку это такая часто используемая функция R. Хотя R знает, хорошо, что вы имеете в виду, когда ссылаетесь, вполне возможно, что это можно обмануть, и устранение неполадок будет проблематичным c. Поэтому я назвал это mylist здесь.)

mylist <- c("TI  - a", "AU  - b", "ER  -", " ",
            "TI  - c", "AU  - d", "ER  -", " ",
            "TI  - e", "AU  - f", "ER  -")
non_ER_runs <- rle(mylist == "ER  -")
non_ER_runs
# Run Length Encoding
#   lengths: int [1:6] 2 1 3 1 3 1
#   values : logi [1:6] FALSE TRUE FALSE TRUE FALSE TRUE

RLE говорит нам сколько в каждой категории. Для нас категория «соответствует и не соответствует». Вектор $values здесь говорит нам, что первые элементы не не совпадают (FALSE), и их два. Вторая партия соответствует (TRUE) и имеет длину 1. Et c.

inds <- cumsum(non_ER_runs$lengths)
newlist <- mapply(function(a,b) mylist[a:b], c(1, 1+head(inds, n=-1)), inds)
newlist
# [[1]]
# [1] "TI  - a" "AU  - b"
# [[2]]
# [1] "ER  -"
# [[3]]
# [1] " "       "TI  - c" "AU  - d"
# [[4]]
# [1] "ER  -"
# [[5]]
# [1] " "       "TI  - e" "AU  - f"
# [[6]]
# [1] "ER  -"

Итак, мы разбили каждую партию на собственный вектор. Используя возврат из rle снова, мы можем выбрать только те элементы, к которым мы хотим что-то добавить:

newlist[ non_ER_runs$values ]
# [[1]]
# [1] "ER  -"
# [[2]]
# [1] "ER  -"
# [[3]]
# [1] "ER  -"
Map(function(vec, vec2) c(vec, vec2),
      newlist[ non_ER_runs$values ],
      sprintf("ID  - %i", seq_along(newlist[ non_ER_runs$values ])))
# [[1]]
# [1] "ER  -"   "ID  - 1"
# [[2]]
# [1] "ER  -"   "ID  - 2"
# [[3]]
# [1] "ER  -"   "ID  - 3"

Теперь нужно просто заменить элементы списка новыми элементами, а затем unlist

newlist[ non_ER_runs$values ] <-
  Map(function(vec, vec2) c(vec, vec2),
      newlist[ non_ER_runs$values ],
      sprintf("ID  - %i", seq_along(newlist[ non_ER_runs$values ])))
newlist <- unlist(newlist)
newlist
#  [1] "TI  - a" "AU  - b" "ER  -"   "ID  - 1" " "      
#  [6] "TI  - c" "AU  - d" "ER  -"   "ID  - 2" " "      
# [11] "TI  - e" "AU  - f" "ER  -"   "ID  - 3"
0 голосов
/ 20 февраля 2020
ris <- c("TI  - a", "AU  - b", "ER  -", " ",
          "TI  - c", "AU  - d", "ER  -", " ",
          "TI  - e", "AU  - f", "ER  -")

Еще одно предложение с использованием грязных циклов for;)

1.Найдите позицию для вставки элемента ID ранее (здесь используется немного регулярных выражений). Используйте вектор pos для генерации нужного количества идентификаторов:

pos <- grep("^ER", ris)
ids <- paste0("ID = ", seq_along(pos))

2.L oop через все позиции, вставьте, вставьте, повторите (и обновите pos):

for (i in seq_along(pos)) {
  ris <- c(ris[1:(pos[i]-1)], ids[i], ris[pos[i]:length(ris)] )
  pos <- pos + 1
}

ris

Возвращает:

[1] "TI  - a" "AU  - b" "ID = 1"  "ER  -"  
[5] " "       "TI  - c" "AU  - d" "ID = 2" 
[9] "ER  -"   " "       "TI  - e" "AU  - f"
[13] "ID = 3"  "ER  -"  
0 голосов
/ 20 февраля 2020

Вы можете попробовать:

list[list == "ER  -"] <- paste("ID   -", seq_along(which(list == "ER  -")), "\nER  -")
...