【问题标题】:How to remove a particular repeating element after the first from a character vector如何从字符向量中删除第一个元素之后的特定重复元素
【发布时间】:2017-12-26 10:41:59
【问题描述】:

我有一个路径步骤向量,并且有一个特定的路径步骤,如果它重复,我想消除重复。

例如,

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

现在如果“X”重复,那么我想消除除第一个之外的所有 X 重复,同时保留其余元素的顺序,这样我想要的结果是:

my_vec = "A > A > X > B > X > C > C",其中重复的 X 从中间消除。

我用for循环和if-else组合尝试了这个,这样我会检测向量中的前一个元素是否也包含'X',然后用NA替换元素,然后我可以删除NA项目,但这种方法不能提供预期的结果。

我尝试查看herehere,但它们只是过滤掉了独特的元素,而我想对特定元素执行此操作。

这是我的代码:

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。

【问题讨论】:

    标签: r regex vector


    【解决方案1】:

    1) gsub 用该序列中的最后一个匹配替换任何可能后跟空格和大于字符的重复 X 序列。如果序列在末尾,这也有效。如果我们知道序列不在末尾,例如问题中的示例,那么我们可以将第一个参数简化为"(X &gt; )*"

    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)。

    【讨论】:

    • 太棒了!谢谢!
    【解决方案2】:

    我们可以使用gsub

    gsub("(?:X > )\\K(X > )\\1*", "", my_vec, perl = TRUE)
    #[1] "A > A > X > B > X > C > C"
    

    【讨论】:

    • \\K 是什么?
    • @Frank 是重置匹配的模式
    【解决方案3】:

    没有正则表达式的解决方案。 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 = " > ")
    

    【讨论】:

      【解决方案4】:
      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 需要哪种语言的答案?正则表达式至少没有帮助吗?
      • 它被标记为 R... 并且 R 的正则表达式有点不同。
      • 翻译成 R 这将是:gsub("(\\s*X &gt;)+", " X &gt;", my_vec)
      猜你喜欢
      • 1970-01-01
      • 2019-11-17
      • 1970-01-01
      • 1970-01-01
      • 2019-08-02
      • 2019-11-13
      • 1970-01-01
      • 2019-02-26
      • 1970-01-01
      相关资源
      最近更新 更多