10

I have a vector where I want to replace one element with multiple element, I am able to replace with one but not multuiple, can anyone help?

For example I have

data <- c('a', 'x', 'd')
> data
[1] "a" "x" "d"

I want to replace "x" with "b", "c" to get

[1] "a" "b" "c" "d"

However

gsub('x', c('b', 'c'), data)

gives me

[1] "a" "b" "d"
Warning message:
In gsub("x", c("b", "c"), data) :
  argument 'replacement' has length > 1 and only the first element will 
be used
user1165199
  • 6,351
  • 13
  • 44
  • 60
  • Some of these may apply as well: [How to insert elements into a vector?](https://stackoverflow.com/questions/1493969/how-to-insert-elements-into-a-vector) – Henrik Feb 13 '18 at 14:07

4 Answers4

7

Here's how I would tackle it:

data <- c('a', 'x', 'd')
lst <- as.list(data)
unlist(lapply(lst, function(x) if(x == "x") c("b", "c") else x))
# [1] "a" "b" "c" "d"

We're making use of the fact that list-structures are more flexible than atomic vectors. We can replace a length-1 list-element with a length>1 element and then unlist the result to go back to an atomic vector.

Since you want to replace exact matches of "x" I prefer not to use sub/gsub in this case.

talat
  • 68,970
  • 21
  • 126
  • 157
  • The use of `lapply` here is probably quite a bit slower than vectorised comparison and list splicing, as done in efbbrown’s answer attempt. – Konrad Rudolph Feb 13 '18 at 14:32
  • @KonradRudolph, that's probably true. I haven't said anything about performance (and neither did OP) but I'm positive that this approach returns the correct answer when it finishes. – talat Feb 13 '18 at 14:35
2

You may try this , although I believe the accepted answer is great:

unlist(strsplit(gsub("x", "b c", data), split = " "))

Logic: Replacing "x" with "b c" with space and then doing the strsplit, once its splitted we can convert is again back to vector using unlist.

PKumar
  • 10,971
  • 6
  • 37
  • 52
1

This is a bit tricky of a problem because in your replacement you also want to grow your vector. That being said, I believe this should work:

replacement <- c("b","c")

new_data <- rep(data, times = ifelse(data=="x", length(replacement), 1))
new_data[new_data=="x"] <- replacement

new_data
#[1] "a" "b" "c" "d"

This will also work if you have multiple "x"s in your vector like:

data <- c("a","x","d","x")
Mike H.
  • 13,960
  • 2
  • 29
  • 39
  • Curious as to why this was downvoted. If someone wants to elaborate on why this wrong, please let me know – Mike H. Feb 13 '18 at 15:56
0

Another approach:

data <- c('a', 'x', 'd')
pattern <- "x"
replacement <- c("b", "c")

sub_one_for_many <- function(pattern, replacement, x) {
  removal_index <- which(x == pattern)
  if (removal_index > 1) {
    result <- c(x[1:(removal_index-1)], replacement, x[(removal_index+1):length(x)])
  } else if (removal_index == 1) {
    result <- c(replacement, x[2:length(x)])
  }
  return(result)
}

answer <- sub_one_for_many(pattern, replacement, data)

Output:

> answer
[1] "a" "b" "c" "d"
Eugene Brown
  • 4,032
  • 6
  • 33
  • 47