R:从头开始找到最大的公共子串

时间:2014-10-09 17:58:51

标签: r substring

我有两个载体:

word1 <- "bestelling"   
word2 <- "bestelbon"

现在我想找到从beginnig开始的最大公共子字符串,所以这里将是“bestel”。

但是举两个例如“bestelling”和“stel”,然后我想返回""

11 个答案:

答案 0 :(得分:9)

马修普卢德打来电话,基斯马克先生回应! 对不起,BondedDust,但我无法从工作场所墙后面找到生物传导器。

library(microbenchmark)
wfoo1 <-'bestelling'
wfoo2<-'bestelbon'


microbenchmark(stu(wfoo1,wfoo2),nathan(wfoo1,wfoo2),plourde(),scriven(wfoo1,wfoo2),dmt(wfoo1,wfoo2),mrflick(wfoo1,wfoo2),roland(c(wfoo1,wfoo2)))
Unit: microseconds
                    expr     min       lq   median       uq
       stu(wfoo1, wfoo2) 171.905 183.0230 187.5135 191.1490
    nathan(wfoo1, wfoo2)  35.921  42.3360  43.6180  46.1840
               plourde() 551.208 581.3545 591.6175 602.5220
   scriven(wfoo1, wfoo2)  16.678  21.1680  22.6645  23.7335
       dmt(wfoo1, wfoo2)  79.966  86.1665  88.7325  91.5125
   mrflick(wfoo1, wfoo2) 100.492 108.4030 111.1830 113.9625
 roland(c(wfoo1, wfoo2)) 215.950 226.8545 231.7725 237.5455
     max neval
 435.321   100
  59.012   100
 730.809   100
  85.525   100
 286.081   100
 466.537   100
 291.213   100

我认为我有责任修改这些功能,以便他们测量一个输入字,例如,1000个参考字(而不是一对)的矢量,以查看速度测试的进展情况。也许以后。

后来...... :-)。我没有制作循环,但我用长话来试试:

编辑:正如弗洛尔指出的那样,这是一个错字,导致测试一个相当长的向量 很短的话!

wfoo1 <-rep(letters,100)
wfoo2<-c(rep(letters,99),'foo')
Unit: microseconds
                    expr        min          lq      median
       stu(wfoo1, wfoo2)  31215.243  32718.5535  35270.6110
    nathan(wfoo1, wfoo2)    202.266    216.3780    227.2825
               plourde()    569.168    617.0615    661.5340
   scriven(wfoo1, wfoo2)    794.953    828.3070    847.5505
       dmt(wfoo1, wfoo2)   1081.033   1156.9365   1205.8990
   mrflick(wfoo1, wfoo2) 126058.316 131283.4485 241018.5150
 roland(c(wfoo1, wfoo2))    946.759   1004.4885   1045.3260
          uq        max neval
 146451.2595 167000.713   100
    236.0485    356.211   100
    694.6750    795.381   100
    868.9310   1021.594   100
   1307.6740 116075.442   100
 246739.6910 991550.586   100
   1082.1020   1243.103   100

对不起理查德,但看起来你需要把你的鸡肉晚餐交给内森。

EDIT2:确保输入是单个单词,并将flodel的代码添加到堆中。

编辑了&#34; plourde&#34;函数接受输入并重新设置长字大小写

wfoo1 <-paste(rep(letters,100),collapse='')
wfoo2<-paste(c(rep(letters,99),'foo'),collapse='')

看起来像3个人&#39;代码表现相似,所以就像在环法自行车赛中一样,我将第一名奖授予 mrflick,dmt和flodel。

 microbenchmark(stu(wfoo1,wfoo2),nathan(wfoo1,wfoo2),plourde(c(wfoo1,wfoo2)),scriven(wfoo1,wfoo2),dmt(wfoo1,wfoo2),mrflick(wfoo1,wfoo2),roland(c(wfoo1,wfoo2)),flodel(wfoo1,wfoo2) )
Unit: microseconds
                     expr        min          lq     median
        stu(wfoo1, wfoo2)  17786.578  18243.2795  18420.317
     nathan(wfoo1, wfoo2)  36651.195  37703.3625  38095.493
 plourde(c(wfoo1, wfoo2)) 183616.029 187673.5350 190706.457
    scriven(wfoo1, wfoo2)  17546.253  17994.1890  18244.990
        dmt(wfoo1, wfoo2)    737.651    781.0550    821.466
    mrflick(wfoo1, wfoo2)    870.643    951.4630    976.479
  roland(c(wfoo1, wfoo2))  99540.947 102644.2115 103654.258
     flodel(wfoo1, wfoo2)    666.239    705.5795    717.553
         uq         max neval
  18602.270   20835.107   100
  38450.848  155422.375   100
 303856.952 1079715.032   100
  18404.281   18992.905   100
    853.751    1719.047   100
   1012.186  116669.839   100
 105423.123  226522.073   100
    732.947     822.748   100

答案 1 :(得分:6)

fun <- function(words) {
  #extract substrings from length 1 to length of shortest word
  subs <- sapply(seq_len(min(nchar(words))), 
                 function(x, words) substring(words, 1, x), 
                 words=words)
  #max length for which substrings are equal
  neqal <- max(cumsum(apply(subs, 2, function(x) length(unique(x)) == 1L)))
  #return substring
  substring(words[1], 1, neqal)
}

words1 <- c("bestelling", "bestelbon")
fun(words1)
#[1] "bestel"

words2 <- c("bestelling", "stel")
fun(words2)
#[1] ""

答案 2 :(得分:5)

这是另一个似乎有用的功能。

foo <- function(word1, word2) {
    s1 <- substring(word1, 1, 1:nchar(word1))
    s2 <- substring(word2, 1, 1:nchar(word2))
    if(length(w <- which(s1 %in% s2))) s2[max(w)] else character(1)
}

foo("bestelling", "bestelbon")
# [1] "bestel"
foo("bestelling", "stel")
# [1] ""
foo("bestelbon", "bestieboop")
# [1] "best"
foo("stel", "steal")
# [1] "ste"

答案 3 :(得分:5)

flodel <- function(word1, word2) {
   # the length of the shorter word
   n <- min(nchar(word1), nchar(word2))
   # two vectors of characters of the same length n
   c1 <- strsplit(word1, "", fixed = TRUE)[[1]][1:n]
   c2 <- strsplit(word2, "", fixed = TRUE)[[1]][1:n]
   # a vector that is TRUE as long as the characters match
   m <- as.logical(cumprod(c1 == c2))
   # the answer
   paste(c1[m], collapse = "")
}

答案 4 :(得分:4)

这适用于单词的任意向量

words <- c('bestelling', 'bestelbon')
words.split <- strsplit(words, '')
words.split <- lapply(words.split, `length<-`, max(nchar(words)))
words.mat <- do.call(rbind, words.split)
common.substr.length <- which.max(apply(words.mat, 2, function(col) !length(unique(col)) == 1)) - 1
substr(words[1], 1, common.substr.length)
# [1] "bestel"

答案 5 :(得分:4)

为什么不添加另一个!并且破解它所以答案不同于每个人!

largestStartSubstr<-function(word1, word2){ 
    word1vec<-unlist(strsplit(word1, "", fixed=TRUE))
    word2vec<-unlist(strsplit(word2, "", fixed=TRUE))
    indexes<-intersect(1:nchar(word1), 1:nchar(word2))
    bools<-word1vec[indexes]==word2vec[indexes]
    if(bools[1]==FALSE){
        ""
    }else{
        lastChar<-match(1,c(0,diff(cumsum(!bools))))-1
        if(is.na(lastChar)){
            lastChar<-indexes[length(indexes)]
        }
        substr(word1, 1,lastChar)
    }
}

word1 <- "bestselling"
word2<- "bestsel"

largestStartSubstr(word1, word2)
#[1] "bestsel"

word1 <- "bestselling"
word2<- "sel"

largestStartSubstr(word1, word2)
#[1] ""

答案 6 :(得分:4)

尽管我通常避免使用R中的for循环 - 假设你从一开始就开始并一直持续到找到解决方案,这似乎是一种简单的方法。

它比我认为的其他一些例子更直观

lcsB <- function(string1, string2) {
    x <- ''
    for (i in 1:nchar(string1)){
        if (substr(string1[1],1,i) == substr(string2[1],1,i)) {
            x <- substr(string1[1],1,i)
        }
        else
            return(x)
        }
    return(x)
}

lcsB("bestelling", "bestelbon")
lcsB("bestelling", "stel")

答案 7 :(得分:3)

这似乎有效

longestprefix<-function(a,b) {
    n <- pmin(nchar(a), nchar(b))
    mapply(function(x, y, n) {
        rr<-rle(x[1:n]==y[1:n])
        if(rr$values[1]) {
            paste(x[1:rr$lengths[1]], collapse="")
        } else {
            ""
        }
    }, strsplit(a, ""), strsplit(b,""), n)
}



longestprefix("bestelling", "bestelbon")
# [1] "bestel"
longestprefix("bestelling", "stel")
# [1] ""

答案 8 :(得分:3)

我意识到我迟到了这个派对,但确定成对排列是生物学研究中的一个基本问题,并且已经存在一个攻击这个问题的包(或包家族)。名为Biostrings的Bioconductor软件包是可用的(至少如果你安装了所有的默认依赖项,它就很大了,所以在安装过程中需要耐心)。它返回S4对象,因此需要不同的提取功能。这可能是一个提取坚果的大锤,但这里是给出所需结果的代码:

install.packages("Biostrings", repo="http://www.bioconductor.org/packages/2.14/bioc/", dependencies=TRUE)
library(Biostrings)
psa1 <- pairwiseAlignment(pattern = c(word1) ,word2,type="local")
psa1@pattern
#[1] bestel 

但是,它没有设置为默认为两个字符串的第一个字符的匹配限制。我们希望@MartinMorgan能够解决我的错误。

答案 9 :(得分:2)

一些正则表达式可以做到这一点:

sub('^([^|]*)[^|]*(?:\\|\\1[^|]*)$', '\\1', paste0(word1, '|', word2))
#[1] "bestel"

我使用|作为分隔符 - 选择一个对你的字符串有用的内容。

答案 10 :(得分:1)

有点乱,但这是我提出的:

largest_subset <- Vectorize(function(word1,word2) {
    substr(word1, 1, sum(substring(word1, 1, 1:nchar(word1))==substring(word2, 1, 1:nchar(word2))))
})

如果单词的长度不同,则会产生警告信息,但不必担心。它检查每个单词的第一个字符到每个位置的每个子字符串是否在两个单词之间产生匹配。然后,您可以计算出多少值为真,并将子字符串捕获到该字符。我将其矢量化,以便将其应用于单词向量。

> word1 <- c("tester","doesitwork","yupyppp","blanks")
> word2 <- c("testover","doesit","yupsuredoes","")
> largest_subset(word1,word2)
    tester doesitwork    yupyppp     blanks 
    "test"   "doesit"      "yup"         ""