Как найти самый длинный непрерывный непрерывный набор символов в строке на основе заданного вектора

У меня есть следующая строка в коде R.

aas <- "QAWDIIKRIDKK"

И я хочу проверить самый длинный непрерывный фрагмент этой строки, содержащий символ в следующем векторе:

hydrophobic_res <- c("W", "F", "I", "L", "V", "M", "C", "A", "G")

Ответ:

AW, II

Другой пример:

QFILVMD -> FILVM

Как я могу сделать это в R?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
0
115
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Один из вариантов - разделить строку, заменить несоответствующие элементы из ключевого вектора на 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"

Другие вопросы по теме