У меня есть следующая строка в коде R.
aas <- "QAWDIIKRIDKK"
И я хочу проверить самый длинный непрерывный фрагмент этой строки, содержащий символ в следующем векторе:
hydrophobic_res <- c("W", "F", "I", "L", "V", "M", "C", "A", "G")
Ответ:
AW, II
Другой пример:
QFILVMD -> FILVM
Как я могу сделать это в R?





Один из вариантов - разделить строку, заменить несоответствующие элементы из ключевого вектора на NA, выполнить группировку по paste на основе созданного NA и подмножить элементы на основе maximum количества символов
f1 <- function(str1, matchvec)
{
v1 <- strsplit(str1, "")[[1]]
v1[!v1 %in% matchvec] <- NA
v2 <- tapply(v1, with(rle(!is.na(v1)),
rep(seq_along(values), lengths)),
FUN = function(x) paste(x[!is.na(x)], collapse = ""))
unname(v2[nchar(v2) == max(nchar(v2))])
}
-тестирование
> f1(aas, hydrophobic_res)
[1] "AW" "II"
> f1("QFILVMD", hydrophobic_res)
[1] "FILVM"
Опция на основе регулярных выражений — создайте шаблон для удаления всех тех символов, которых нет в matchvec, с помощью gsub, разделения и подмножества на основе количества символов.
f2 <- function(str1, matchvec)
{
pat <- sprintf("[^%s]", paste(matchvec, collapse = ""))
v1 <- strsplit(gsub(pat, ",", str1), ",")[[1]]
v1[nchar(v1) == max(nchar(v1))]
}
-тестирование
> f2(aas, hydrophobic_res)
[1] "AW" "II"
> f2("QFILVMD", hydrophobic_res)
[1] "FILVM"
Вот альтернативный способ: мне проще решить такую задачу, думая о табличках или фреймах данных:
library(data.table)
library(dplyr)
str_split(aas, "")[[1]] %>%
as_tibble() %>%
mutate(flag = grepl(paste(hydrophobic_res, collapse = "|"), value)) %>%
group_by(group = rleid(flag==TRUE)) %>%
filter(flag == TRUE & max(row_number() > 1)) %>%
mutate(string = paste(value, collapse = "")) %>%
slice(1) %>%
pull(string)
[1] "AW" "II"
Как вы упомянули, скорость важна, рассмотрите возможность использования stringi, оптимизированного для такого рода задач. Преимущество заключается в том, что его также легко векторизовать:
library(stringi)
find_longest <- function(strng, pat) {
pats <- if (is.list(pat)) {
sapply(pat, \(x) stri_join(c("[", x, "]+"), collapse = ""))
} else {
stri_join(c("[", pat, "]+"), collapse = "")
}
res <- stri_extract_all(strng, regex = pats)
lapply(res, \(x) {
nc <- nchar(x)
x[nc == max(nc)]
})
}
hydrophobic_res <- c("W", "F", "I", "L", "V", "M", "C", "A", "G")
aas <- "QAWDIIKRIDKK"
aas2 <- "QFILVMD"
find_longest(c(aas, aas2), hydrophobic_res)
[[1]]
[1] "AW" "II"
[[2]]
[1] "FILVM"
Я бы предложил сделать это так. Не тестировал его, но, поскольку он использует векторизованные операции, он, вероятно, должен быть достаточно быстрым.
library(stringr)
get_longest_fragment <- function(aa, res) {
aa_vec <- str_split_1(aa, "")
delta <- diff(c(FALSE, aa_vec %in% res))
# find start and end of TRUE stretches
starts <- which(delta == 1)
ends <- which(delta == -1) - 1
len <- ends - starts
longest <- len == max(len)
# index the aa sequence
str_sub(aa, starts[longest], ends[longest])
}
get_longest_fragment(aa_sequence, hydrophobic_res)
#> [1] "AW" "II"