R 通过索引快速替换字符串中的多个字符

R 通过索引快速替换字符串中的多个字符,r,string,dplyr,stringi,R,String,Dplyr,Stringi,我正在尝试用另一个字符快速替换字符串中的多个字符,例如* 例如,我有一个字符串,如: string = "abcdefghij" 我还有一个索引向量,指示我想用另一个字符替换上面字符串中的字母的位置 string_indexes_replaced = c(1, 4, 6, 9) 期望输出: 我所做的 我尝试了一种非常新手式的方法,将字符拆分成一个列表,用*替换字符,然后将列表折叠回所需的字符串,如下所示: library(dplyr) library(stringi) string%>

我正在尝试用另一个字符快速替换字符串中的多个字符,例如*

例如,我有一个字符串,如:

string = "abcdefghij"
我还有一个索引向量,指示我想用另一个字符替换上面字符串中的字母的位置

string_indexes_replaced = c(1, 4, 6, 9)
期望输出:

我所做的

我尝试了一种非常新手式的方法,将字符拆分成一个列表,用*替换字符,然后将列表折叠回所需的字符串,如下所示:

library(dplyr)
library(stringi)

string%>%
strsplit(split = "")%>%
lapply(function(x) replace(x, string_indexes_replaced, rep("*", length(string_indexes_replaced))))%>%
lapply(stri_flatten)%>%
unlist(use.names = FALSE)
哪个输出

"*bc*e*gh*j"
但很明显,应该有比我上面发布的内容更简单、更快的内容。有什么比我在这里演示的更简单、更快的吗?

我们可以使用子字符串

我们可以使用子字符串

在BaseR中,除了所示的substring和for循环方法外,还可以使用utf8ToInt和intToUtf8来实现它

v <- utf8ToInt(string)
v[string_indexes_replaced ] <- utf8ToInt("*")
res <- intToUtf8(v)
在BaseR中,除了所示的substring和for循环方法外,还可以使用utf8ToInt和intToUtf8来实现它

v <- utf8ToInt(string)
v[string_indexes_replaced ] <- utf8ToInt("*")
res <- intToUtf8(v)

一个简单的递归解决方案。时间效率应该与循环的迭代相同。好处是没有副作用,整数ks的赋值是本地化的,这样我们就可以把它的整个计算作为一个函数抽象来处理,并将它提供给我们正在处理的更大程序的其他部分。这将有助于模块化代码

# multi-replace for character vector input with length greater than 1
multi_replace_v <- function(v, r, ks) {
  ks <- as.integer(ks)
  if (length(ks) == 0) {
    v
  } else if (length(ks) == 1) {
    if (ks[[1]] > length(v) | ks[[1]] < 1) {
      stop("Invalid parameter: ks=", as.character(ks[[1]]), ". Valid range: 1-", as.character(length(v)))
    } else if (ks[[1]] == 1) {
      c(r, v[-1])
    } else if (ks[[1]] == length(v)) {
      c(v[-length(v)], r)
    } else {
      c(v[1:(ks[[1]]-1)], r, v[(ks[[1]]+1):length(v)])
      }
  } else {
    multi_replace_v(multi_replace_v(v, r, ks[[1]]), r, ks[-1])
  }
}

# multi-replace for input of single string character vector
multi_replace_s <- function(s, r, ks) paste0(multi_replace_v(unlist(strsplit(s, '')), r, ks), collapse = '') 

# multi-replace for both single string and long vector input
multi_replace <- function(v_or_s, r, ks) {
  if (length(v_or_s) == 1) {
    multi_replace_s(v_or_s, r, ks)
  } else if (length(v_or_s) > 1) {
    multi_replace_v(v_or_s, r, ks)
  } else {
    NULL
  }
}

# Example
> multi_replace('abcdefghij', "*", c(1,4,6,9))
[1] "*bc*e*gh*j"

一个简单的递归解决方案。时间效率应该与循环的迭代相同。好处是没有副作用,整数ks的赋值是本地化的,这样我们就可以把它的整个计算作为一个函数抽象来处理,并将它提供给我们正在处理的更大程序的其他部分。这将有助于模块化代码

# multi-replace for character vector input with length greater than 1
multi_replace_v <- function(v, r, ks) {
  ks <- as.integer(ks)
  if (length(ks) == 0) {
    v
  } else if (length(ks) == 1) {
    if (ks[[1]] > length(v) | ks[[1]] < 1) {
      stop("Invalid parameter: ks=", as.character(ks[[1]]), ". Valid range: 1-", as.character(length(v)))
    } else if (ks[[1]] == 1) {
      c(r, v[-1])
    } else if (ks[[1]] == length(v)) {
      c(v[-length(v)], r)
    } else {
      c(v[1:(ks[[1]]-1)], r, v[(ks[[1]]+1):length(v)])
      }
  } else {
    multi_replace_v(multi_replace_v(v, r, ks[[1]]), r, ks[-1])
  }
}

# multi-replace for input of single string character vector
multi_replace_s <- function(s, r, ks) paste0(multi_replace_v(unlist(strsplit(s, '')), r, ks), collapse = '') 

# multi-replace for both single string and long vector input
multi_replace <- function(v_or_s, r, ks) {
  if (length(v_or_s) == 1) {
    multi_replace_s(v_or_s, r, ks)
  } else if (length(v_or_s) > 1) {
    multi_replace_v(v_or_s, r, ks)
  } else {
    NULL
  }
}

# Example
> multi_replace('abcdefghij', "*", c(1,4,6,9))
[1] "*bc*e*gh*j"

谢谢@akrun。在接受这个答案之前,我要等一会儿,因为我想看看是否有其他人有其他方法可以很好地按时间扩展较长的字符串,以及这是否应用于字符串列表。@InfiniteFlashChess Ok。我从stringiGreat中又添加了一个选项。谢谢你的努力和时间。你对社区来说是一个很好的资源。你的stri_sub_all系列很棒,但在我为我的任务做了一些基准测试后,比Thomas的慢了一点。谢谢@akrun。在接受这个答案之前,我要等一会儿,因为我想看看是否有其他人有其他方法可以很好地按时间扩展较长的字符串,以及这是否应用于字符串列表。@InfiniteFlashChess Ok。我从stringiGreat中又添加了一个选项。谢谢你的努力和时间。您是社区的重要资源。您的stri_sub_all系列很棒,但在我为我的任务做了一些基准测试之后,您的stri_sub_all系列比Thomas的稍慢了一点。@ThomasIsCoding谢谢您。“如果在那之前还没有更快的解决方案,我明天会把这个标记为可接受的答案。”托马斯科丁,谢谢。如果到那时还没有更快的解决方案,我明天会把这个问题标记为可接受的答案。
> res
[1] "*bc*e*gh*j"
# multi-replace for character vector input with length greater than 1
multi_replace_v <- function(v, r, ks) {
  ks <- as.integer(ks)
  if (length(ks) == 0) {
    v
  } else if (length(ks) == 1) {
    if (ks[[1]] > length(v) | ks[[1]] < 1) {
      stop("Invalid parameter: ks=", as.character(ks[[1]]), ". Valid range: 1-", as.character(length(v)))
    } else if (ks[[1]] == 1) {
      c(r, v[-1])
    } else if (ks[[1]] == length(v)) {
      c(v[-length(v)], r)
    } else {
      c(v[1:(ks[[1]]-1)], r, v[(ks[[1]]+1):length(v)])
      }
  } else {
    multi_replace_v(multi_replace_v(v, r, ks[[1]]), r, ks[-1])
  }
}

# multi-replace for input of single string character vector
multi_replace_s <- function(s, r, ks) paste0(multi_replace_v(unlist(strsplit(s, '')), r, ks), collapse = '') 

# multi-replace for both single string and long vector input
multi_replace <- function(v_or_s, r, ks) {
  if (length(v_or_s) == 1) {
    multi_replace_s(v_or_s, r, ks)
  } else if (length(v_or_s) > 1) {
    multi_replace_v(v_or_s, r, ks)
  } else {
    NULL
  }
}

# Example
> multi_replace('abcdefghij', "*", c(1,4,6,9))
[1] "*bc*e*gh*j"