用于在一组字符串中查找最长公共起始子字符串的R实现

时间:2015-02-02 08:33:06

标签: r string

这个问题只是要求在R中实现以下问题:Find the longest common starting substring in a set of strings(JavaScript)

此问题是最长公共子字符串问题的一个更具体的情况。我只需要找到数组中最长的公共起始子字符串”。

所以我只是在寻找这个问题的R实现(最好不要在JavaScript版本中建议的 for / while循环方式),如果可能的话我想把它包装成一个函数,所以我可以应用于数据表中的许多组。

经过一些搜索,我找不到一个R的例子,因此这个问题。

示例数据: 我有以下字符向量:

dput(data)
c("ADA4417-3ARMZ-R7", "ADA4430-1YKSZ-R2", "ADA4430-1YKSZ-R7", 
"ADA4431-1YCPZ-R2", "ADA4432-1BCPZ-R7", "ADA4432-1BRJZ-R2")

我希望在R 中运行一个算法,它会找到以下输出:ADA44

从我在JavaScript接受的答案中看到的,我们的想法是先对矢量进行排序,提取第一个和最后一个元素(例如:"ADA4417-3ARMZ-R7""ADA4432-1BRJZ-R2",将它们分解为单个字符,并循环通过它们,直到其中一个字符不匹配(希望我正确)

任何帮助都会很棒!

4 个答案:

答案 0 :(得分:7)

从你的建议中汲取灵感,你可以尝试这个功能:

comsub<-function(x) {
    # sort the vector
    x<-sort(x)
    # split the first and last element by character
    d_x<-strsplit(x[c(1,length(x))],"")
    # compute the cumulative sum of common elements
    cs_x<-cumsum(d_x[[1]]==d_x[[2]])
    # check if there is at least one common element
    if(cs_x[1]!=0) {
        # see when it stops incrementing and get the position of last common element
        der_com<-which(diff(cs_x)==0)[1]
        # return the common part
        return(substr(x[1],1,der_com))
    } else { # else, return an empty vector
        return(character(0))
    }
}

更新

遵循@nicola建议,该功能更简单,更优雅的变体:

comsub<-function(x) {
    # sort the vector
    x<-sort(x)
    # split the first and last element by character
    d_x<-strsplit(x[c(1,length(x))],"")
    # search for the first not common element and so, get the last matching one
    der_com<-match(FALSE,do.call("==",d_x))-1
    # if there is no matching element, return an empty vector, else return the common part
    ifelse(der_com==0,return(character(0)),return(substr(x[1],1,der_com)))
}

示例:

使用您的数据

x<-c("ADA4417-3ARMZ-R7", "ADA4430-1YKSZ-R2", "ADA4430-1YKSZ-R7", 
"ADA4431-1YCPZ-R2", "ADA4432-1BCPZ-R7", "ADA4432-1BRJZ-R2")
> comsub(x)
#[1] "ADA44"

当没有共同的起始子串

x<-c("abc","def")
> comsub(x)
# character(0)

答案 1 :(得分:4)

base替代方案,使用lcprefix中的Biostrings函数查找“两个字符串的最长公共前缀[...]”

source("http://bioconductor.org/biocLite.R")
biocLite("Biostrings")
library(Biostrings)

x2 <- sort(x)
substr(x2[1], start = 1, stop = lcprefix(x2[1], x2[length(x2)]))
# [1] "ADA44"

答案 2 :(得分:0)

根据Henrik的回答,Bioconductor具有基于C的前缀功能和基于R的前缀功能。基于R的是:

lcPrefix <- function (x, ignore.case = FALSE) 
{
    x <- as.character(x)
    if (ignore.case) 
        x <- toupper(x)
    nc <- nchar(x, type = "char")
    for (i in 1:min(nc)) {
        ss <- substr(x, 1, i)
        if (any(ss != ss[1])) {
            return(substr(x[1], 1, i - 1))
        }
    }
    substr(x[1], 1, i)
}
<environment: namespace:Biobase>

...并且不需要Bioconductor的任何特殊功能(据我所知)。

---引文---

  

使用Bioconductor编排高通量基因组分析。 W.   Huber,V.J。 Carey,R。Gentleman,...,M。Morgan Nature Methods,
  2015:12,115。

答案 3 :(得分:0)

这是一个紧凑的解决方案:

data<-c("ADA4417-3ARMZ-R7", "ADA4430-1YKSZ-R2", "ADA4430-1YKSZ-R7", "ADA4431-1YCPZ-R2", "ADA4432-1BCPZ-R7", "ADA4432-1BRJZ-R2")

substr(data[1],1,which.max(apply(do.call(rbind,lapply(strsplit(data,''),`length<-`,nchar(data[1]))),2,function(i)!length(unique(i))==1))-1)
[1] "ADA44"