在字符串中创建字母替换的所有组合

Use*_*321 20 combinations r

我有一个字符串"ECET",我想创建所有可能的字符串,我用"X"替换一个或多个字母(除了第一个之外).

所以在这种情况下我的结果是:

> result
[1] "EXET" "ECXT" "ECEX" "EXXT" "EXEX" "ECXX" "EXXX"
Run Code Online (Sandbox Code Playgroud)

关于如何处理这个问题的任何想法?

这不仅可以创建"X"的可能组合/排列,还可以创建如何将它们与现有字符串组合.

Axe*_*man 14

使用以下FUN参数combn:

a <- "ECET"

fun <- function(n, string) {
  combn(nchar(string), n, function(x) {
    s <- strsplit(string, '')[[1]]
    s[x] <- 'X'
    paste(s, collapse = '')
  } )
}
lapply(seq_len(nchar(a)), fun, string = a)
Run Code Online (Sandbox Code Playgroud)
[[1]]
[1] "XCET" "EXET" "ECXT" "ECEX"

[[2]]
[1] "XXET" "XCXT" "XCEX" "EXXT" "EXEX" "ECXX"

[[3]]
[1] "XXXT" "XXEX" "XCXX" "EXXX"

[[4]]
[1] "XXXX"
Run Code Online (Sandbox Code Playgroud)

unlist得到一个矢量.可能有更快的解决方案.

保持第一个字符不变:

paste0(
  substring(a, 1, 1),
  unlist(lapply(seq_len(nchar(a) - 1), fun, string = substring(a, 2)))
)
Run Code Online (Sandbox Code Playgroud)
[1] "EXET" "ECXT" "ECEX" "EXXT" "EXEX" "ECXX" "EXXX"
Run Code Online (Sandbox Code Playgroud)


Moo*_*per 7

这是一个递归解决方案:

f <- function(x,pos=2){
  if(pos <= nchar(x))
    c(f(x,pos+1), f(`substr<-`(x, pos, pos, "X"),pos+1))
  else x
}
f(x)[-1]
# [1] "ECEX" "ECXT" "ECXX" "EXET" "EXEX" "EXXT" "EXXX"
Run Code Online (Sandbox Code Playgroud)

或使用expand.grid:

do.call(paste0, expand.grid(c(substr(x,1,1),lapply(strsplit(x,"")[[1]][-1], c, "X"))))[-1]
# [1] "EXET" "ECXT" "EXXT" "ECEX" "EXEX" "ECXX" "EXXX"
Run Code Online (Sandbox Code Playgroud)

或使用combn/ Reduce/ substr<-:

combs <- unlist(lapply(seq(nchar(x)-1),combn, x =seq(nchar(x))[-1],simplify = F),F)
sapply(combs, Reduce, f= function(x,y) `substr<-`(x,y,y,"X"), init = x)
# [1] "EXET" "ECXT" "ECEX" "EXXT" "EXEX" "ECXX" "EXXX"
Run Code Online (Sandbox Code Playgroud)

第二个解决方案

pairs0 <- lapply(strsplit(x,"")[[1]][-1], c, "X") # pairs of original letter + "X"
pairs1 <- c(substr(x,1,1), pairs0)                # including 1st letter (without "X")
do.call(paste0, expand.grid(pairs1))[-1]          # expand into data.frame and paste
Run Code Online (Sandbox Code Playgroud)


Ten*_*bai 6

为了使用二进制逻辑添加另一个选项的目的:

假设你的字符串总是4个字符长:

input<-"ECET"
invec <- strsplit(input,'')[[1]]
sapply(1:7, function(x) {
  z <- invec
  z[rev(as.logical(intToBits(x))[1:4])] <- "X"
  paste0(z,collapse = '')
})

[1] "ECEX" "ECXT" "ECXX" "EXET" "EXEX" "EXXT" "EXXX"
Run Code Online (Sandbox Code Playgroud)

如果字符串必须更长,你可以计算幂为2的值,这样的事情应该做:

input<-"ECETC"
pow <- nchar(input)
invec <- strsplit(input,'')[[1]]
sapply(1:(2^(pow-1) - 1), function(x) {
  z <- invec
  z[rev(as.logical(intToBits(x))[1:(pow)])] <- "X"
  paste0(z,collapse = '')
})

[1] "ECETX" "ECEXC" "ECEXX" "ECXTC" "ECXTX" "ECXXC" "ECXXX" "EXETC" "EXETX" "EXEXC" "EXEXX" "EXXTC" "EXXTX" "EXXXC"
[15] "EXXXX"
Run Code Online (Sandbox Code Playgroud)

想法是知道可能的改变的数量,它是3个位置的二进制,所以2 ^ 3减1,因为我们不想保留无替换字符串:7

intToBits返回整数的二进制值,为5:

> intToBits(5)
 [1] 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Run Code Online (Sandbox Code Playgroud)

R默认使用32位,但我们只想要一个与我们的字符串长度相对应的逻辑向量,所以我们只保留原始字符串的nchar.然后我们转换为逻辑并反转这4个布尔值,因为我们永远不会触发最后一位(8个4个字符)它永远不会是真的:

> intToBits(5)
 [1] 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> tmp<-as.logical(intToBits(5)[1:4])
> tmp
[1]  TRUE FALSE  TRUE FALSE
> rev(tmp)
[1] FALSE  TRUE FALSE  TRUE
Run Code Online (Sandbox Code Playgroud)

为了避免覆盖我们的原始向量,我们将其复制到z中,然后使用此逻辑向量替换z中的位置.

对于一个不错的输出,我们返回paste0,其中包含折叠,无需重新创建单个字符串并检索字符向量.