12

I would like to replace different values in a vector with specific other values at once.

In the problem I'm working through:

  • 1 should be replaced with 2,
  • 2 with 4,
  • 3 with 6,
  • 4 with 8,
  • 5 with 1,
  • 6 with 3,
  • 7 with 5 and
  • 8 with 7.

So that:

x <- c(4, 2, 0, 7, 5, 7, 8, 9)
x
[1] 4 2 0 7 5 7 8 9

would be converted to:

[1] 8 4 0 5 1 5 7 9

after the replacements.

I have tried using:

x[x == 1] <- 2
x[x == 2] <- 4

and so on, but that results in 1 getting replaced with 7.

What is the simplest solution to this problem without using any packages?

Jaap
  • 81,064
  • 34
  • 182
  • 193
LatteMaster
  • 165
  • 1
  • 1
  • 7
  • limited to single digit numbers, but interesting: `type.convert(strsplit(chartr(paste(1:8, collapse = ''), paste(c(2, 4, 6, 8, 1, 3, 5, 7), collapse = ''), paste(x, collapse = '')), '')[[1]])` – alistaire Jun 17 '18 at 17:11
  • See e.g. "a more general approach" in [the accepted answer in the first link](https://stackoverflow.com/a/16228315/1851712). – Henrik Jun 17 '18 at 20:08
  • The 'indexing a named vector' approach in the [second link](https://stackoverflow.com/a/7548031/1851712) would in your case be `setNames(c(0,2,4,6,8,1,3,5,7,9), 0:9)[as.character(x)]` – Henrik Jun 17 '18 at 20:15

2 Answers2

15

A possible solution using match:

old <- 1:8
new <- c(2,4,6,8,1,3,5,7)

x[x %in% old] <- new[match(x, old, nomatch = 0)]

which gives:

> x
[1] 8 4 0 5 1 5 7 9

What this does:

  • Create two vectors: old with the values that need to be replaced and new with the corresponding replacements.
  • Use match to see where values from x occur in old. Use nomatch = 0 to remove the NA's. This results in an indexvector of the position in old for the x values
  • This index vector can then be used to index new.
  • Only assign the values from new to the positions of x that are present in old: x[x %in% old]
Jaap
  • 81,064
  • 34
  • 182
  • 193
  • 1
    Or `c(new, x)[match(x, c(old, x))]` as described here: [Multiple replacement in R](https://stackoverflow.com/a/16228315/1851712) – Henrik Jun 17 '18 at 19:46
7

If one can define conversion pair for all values then converting to factor and then back to integer can be an option.

old <- 0:9
new <- c(0,2,4,6,8,1,3,5,7,9)

as.integer(as.character(factor(x, old, new)))
# [1] 8 4 0 5 1 5 7 9
MKR
  • 19,739
  • 4
  • 23
  • 33