如何从字符向量中删除第一个重复元素后的特定重复元素

3
我是一位有用的助手,可以进行文本翻译。以下是需要翻译的内容:

我有一个路径步骤的向量,如果其中有一个特定的路径步骤重复出现,我希望消除这些重复。

例如:

my_vec = "A > A > X > B > X > X > X > C > C"

现在,如果“X”重复出现,我想要除了第一个“X”之外消除所有重复的“X”,同时保留其余元素的顺序,使得我的期望结果是:my_vec = "A > A > X > B > X > C > C",其中重复的X从中间消除。
我尝试使用for循环和if-else组合来实现这一点,以便检测向量中的前一个元素是否也包含'X',然后用NA替换该元素,然后我可以删除NA项目,但这种方法不能提供所需的结果。
我尝试在这里这里查找,但这些只过滤唯一的元素,而我想对特定的元素执行此操作。
以下是我的代码:
my_vec <- unlist(str_split(my_vec, '>') )

for (i in length(my_vec)){
if (grepl('X', my_vec[i]) & grepl('X', my_vec[i-1])) {
    steps[i] <- NA

} else {
    next()
}}
my_new_vec <- str_c(steps, collapse = '>')

然而,输出结果与输入完全相同,没有任何变成NA的改变。
4个回答

5

1) gsub 函数可以将重复的 X 序列(可能跟着空格和大于号字符)替换成该序列中最后一个匹配的 X。即使该序列在字符串末尾也可以被处理。如果我们知道该序列不在字符串末尾,例如问题示例中的情况,那么我们可以简化第一个参数为 "(X > )*"

gsub("(X[> ]*)*", "\\1", my_vec)
## [1] "A > A > X > B > X > C > C"

2) strsplit/rle 如果你想使用与问题中代码相同的strsplit,请尝试将其与rle结合使用。首先执行strsplit生成as,然后应用rle获取r。现在,对于每个" X "运行,将其长度更改为1并将运行反向,以将去重版本的ss作为s。最后转换为字符串并删除前导和尾随空格。

ss <- strsplit(paste0(" ", my_vec, " "), ">")[[1]]
r <- rle(ss)
r$lengths[r$values == " X "] <- 1
s <- inverse.rle(r)
trimws(paste(s, collapse = ">"))
##  "A > A > X > B > X > C > C"

(2a) 使用strsplit的另一种方法如下。这里的第一行和最后一行与(2)中的第一行和最后一行相同。

ss <- strsplit(paste0(" ", my_vec, " "), ">")[[1]]
s <- ss[!c(FALSE, ss[-1] == ss[-length(ss)] & ss[-1] == " X ")]
trimws(paste(s, collapse = ">"))
##  "A > A > X > B > X > C > C"

更新:处理序列位于末尾的情况,并添加(2)和(2a)。


太棒了!谢谢! - Edgar

2
我们可以使用 gsub
gsub("(?:X > )\\K(X > )\\1*", "", my_vec, perl = TRUE)
#[1] "A > A > X > B > X > C > C"

\\K 是什么? - Frank
1
@Frank 这是重置匹配模式。 - akrun

0
一种不使用正则表达式的解决方案。最终输出为my_vec4
# Create example string
my_vec <- "A > A > X > B > X > X > X > C > C"

library(dplyr)

# Split my_vec by " > "
my_vec2 <- strsplit(my_vec, split = " > ")[[1]]

# Same as the previous one and equal to X
X_logi <- my_vec2 == dplyr::lag(my_vec2) & my_vec2 %in% "X"

# Subset my_vec2 if X_logi is false
my_vec3 <- my_vec2[!X_logi]

# Concatenate my_vec3
my_vec4 <- paste(my_vec3, collapse = " > ")

0
let str = "A > A > X > B > X > X > X > C > C";
let result = str.replace(/(\s*X >)+/g, " X >");

console.log(result);  // A > A > X > B > X > C > C

翻译成R语言的代码如下:gsub("(\s*X >)+", " X >", my_vec) – G. Grothendieck


OP想要用哪种语言回答问题?正则表达式没有帮助吗? - JBone
它被标记为R...而且R的正则表达式有点不同。 - Dason
翻译成R语言,应该是这样的:gsub("(\\s*X >)+", " X >", my_vec) - G. Grothendieck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接