rstring

Adding 1 to the last and second last numbers in my data


I have the following data to which I am trying to as 1 to the last section of numbers split by a -. My data is as follows;

dat
"4-3" "60-0 2-5" "10-1 3-2" "20-2 3-0" "3-0" "20-5 3-0"

What I am trying to archive, here we are separately adding 1 to the last number and 1 to the second last number;

dat1
"5-3" "60-0 3-5" "10-1 4-2" "20-2 4-0" "4-0" "20-5 4-0"

dat2
"4-4" "60-0 2-6" "10-1 3-3" "20-2 3-1" "3-1" "20-5 3-1"

I think it might be possible to split the data out using a gsub(), although this could be tricky as my data varies in length between 1 set of numbers and 2, my other issue is that if I use a gsub I'm then unable to add (as far as im aware). My theory would be something like identify the last number and add 1, then identify the second last number and add 1


Solution

  • 1) gsubfn gsubfn is like gsub except that the replacement argument can be a function and, as here, it can optionally be expressed using a compact formula notation. The capture groups in the regular expression are passed to the function and the free variables in the body are assigned to them in order of occurrence. The output of the function then replaces the portion matched by the regular expression.

    library(gsubfn)
    
    res1 <- gsubfn("(\\d+)(-\\d+)$", ~ paste0(as.numeric(x) + 1, y), dat)
    identical(res1, dat1)
    ## [1] TRUE
    
    res2 <- gsubfn("(\\d+)$", ~ as.numeric(x) + 1, dat)
    identical(res2, dat2)
    ## [1] TRUE
    

    2) Base R Uinsg only base R define plus1 to take one component of dat, split it into a numeric vector num increment the element k from the end (k = 1 means last, k = 2 means second last) by 1 and then paste it back togehter. Finally split the input by non-digits and apply plus1.

    plus1 <- function(x, k, num = as.numeric(x))
      replace(num, length(num) - k + 1, tail(num, k)[1] + 1) |>
        matrix(2) |>
        apply(2, paste, collapse = "-") |>
        paste(collapse = " ")
    
    base1 <- sapply(strsplit(dat, "\\D+"), plus1, k = 2)
    identical(base1, dat1)
    ## [1] TRUE
    
    base2 <- sapply(strsplit(dat, "\\D+"), plus1, k = 1)
    identical(base2, dat2)
    ## [1] TRUE
    

    Note

    dat <- c("4-3", "60-0 2-5", "10-1 3-2", "20-2 3-0", "3-0", "20-5 3-0")
    dat1 <- c("5-3", "60-0 3-5", "10-1 4-2", "20-2 4-0", "4-0", "20-5 4-0")
    dat2 <- c("4-4", "60-0 2-6", "10-1 3-3", "20-2 3-1", "3-1", "20-5 3-1")