Использование информации @RichardScriven о том, что adist
можно использовать ( он вычисляет приблизительное расстояние между строками. Я сделал функцию более полной. Обратите внимание, что "trafos"
означает преобразования, используемые для определения расстояния между двумя строками (пример внизу)
ИЗМЕНИТЬ Этот ответ может привести к неправильным/неожиданным результатам; как указано @wdkrnls:
Я запустил вашу функцию против яблока и больших яблочных рогаликов, и она вернула appl. Я бы ожидал яблоко.
Смотрите объяснение неправильного результата ниже. Начнем с функции для получения longest_string
в списке:
longest_string <- function(s){return(s[which.max(nchar(s))])}
Затем мы можем использовать работу @RichardSriven и библиотеку stringi
:
library(stringi)
lcsbstr <- function(a,b) {
sbstr_locations<- stri_locate_all_regex(drop(attr(adist(a, b, counts=TRUE), "trafos")), "M+")[[1]]
cmn_sbstr<-stri_sub(longest_string(c(a,b)), sbstr_locations)
longest_cmn_sbstr <- longest_string(cmn_sbstr)
return(longest_cmn_sbstr)
}
Или мы можем переписать наш код, чтобы избежать использования каких-либо внешних библиотек (по-прежнему используя родную функцию R adist
):
lcsbstr_no_lib <- function(a,b) {
matches <- gregexpr("M+", drop(attr(adist(a, b, counts=TRUE), "trafos")))[[1]];
lengths<- attr(matches, 'match.length')
which_longest <- which.max(lengths)
index_longest <- matches[which_longest]
length_longest <- lengths[which_longest]
longest_cmn_sbstr <- substring(longest_string(c(a,b)), index_longest , index_longest + length_longest - 1)
return(longest_cmn_sbstr )
}
Обе приведенные выше функции идентифицируют только 'hello '
как самую длинную общую подстроку вместо 'hello r'
(независимо от того, какой аргумент длиннее из двух):
identical('hello',
lcsbstr_no_lib('hello', 'hello there'),
lcsbstr( 'hello', 'hello there'),
lcsbstr_no_lib('hello there', 'hello'),
lcsbstr( 'hello there', 'hello'))
ПОСЛЕДНИЕ ИЗМЕНЕНИЯ Обратите внимание на странное поведение с этим результатом:
lcsbstr('hello world', 'hello')
#[1] 'hell'
Я ожидал 'hello'
, но поскольку преобразование фактически перемещает (через удаление) o в миреorld, чтобы стать o в адуo -- только ад часть считается совпадением в соответствии с M
:
drop(attr(adist('hello world', 'hello', counts=TRUE), "trafos"))
#[1] "MMMMDDDMDDD"
#[1] vvvv v
#[1] "hello world"
Такое поведение наблюдается с помощью инструмента Левенштейна — он дает два возможных решения: эквивалентно этим двум преобразованиям
#[1] "MMMMDDDMDDD"
#[1] "MMMMMDDDDDD"
Я не знаю, можем ли мы настроить adist
так, чтобы одно решение предпочиталось другому? (преобразования имеют одинаковый вес - одинаковое количество M и D - не знаю, как предпочесть преобразования с большим числом последовательных M
)
Наконец, не забывайте, что adist позволяет передавать ignore.case = TRUE
(по умолчанию FALSE
).
- Ключ к свойству
"trafos"
объекта adist
; преобразования для перехода от одной строки к другой:
последовательности преобразования возвращаются как атрибут trafos возвращаемого значения, как строки символов с элементами M
, I
, D
и S
, указывающими совпадение, вставку, удаление и замену
person
The Red Pea
schedule
28.10.2015
LCS
qualV находит не самую длинную общую подстроку, она находит самую длинную общую подпоследовательность — отсюда и результат, который вы получаете. Это определение подпоследовательности. Эти проблемы связаны, но имеют совершенно разные решения, а самая длинная общая задача subsequence является более классической задачей в информатике и, следовательно, чаще реализуется. - person Konrad Rudolph   schedule 01.02.2015