Reputation: 61057
I'm looking for a function which will replace all occurrences of one value with another value. For example I'd like to replace all zeros with ones. I don't want to have to store the result in a variable, but want to be able to use the vector anonymously as part of a larger expression.
I know how to write a suitable function myself:
> vrepl <- function(haystack, needle, replacement) {
+ haystack[haystack == needle] <- replacement
+ return(haystack)
+ }
>
> vrepl(c(3, 2, 1, 0, 4, 0), 0, 1)
[1] 3 2 1 1 4 1
But I'm wondering whether there is some standard function to do this job, preferrably from the base
package, as an alternative from some other commonly used package. I believe that using such a standard will likely make my code more readable, and I won't have to redefine that function wherever I need it.
Upvotes: 53
Views: 219486
Reputation: 11024
A simple way to do this is using base ifelse
, which is vectorized (there's also if_else
from dplyr that handles missing values). If the condition is satisfied, we use a replacement value, otherwise we use the original value.
v <- c(3, 2, 1, 0, 4, 0)
ifelse(v == 0, 1, v)
We can avoid a named variable by using a pipe.
c(3, 2, 1, 0, 4, 0) %>% ifelse(. == 0, 1, .)
A common task is to do multiple replacements. Instead of nested ifelse
statements, we can use case_when
from dplyr:
case_when(v == 0 ~ 1,
v == 1 ~ 2,
TRUE ~ v)
Old answer:
For factor or character vectors, we can use revalue
from plyr
:
> revalue(c("a", "b", "c"), c("b" = "B"))
[1] "a" "B" "c"
This has the advantage of only specifying the input vector once, so we can use a pipe like
x %>% revalue(c("b" = "B"))
Upvotes: 5
Reputation: 52349
If someone is looking for a dplyr
alternative to replace
, case_match
is a simple variant to case_when
that works on vectors. It is available since 1.1.0
.
x = c(3, 2, 1, 0, 4, 0)
case_match(x, 0 ~ 1, .default = x)
#[1] 3 2 1 1 4 1
It can also work with multiple replacements:
x = c(3, 2, 1, 0, 4, 0)
case_match(x,
c(0, 2, 4) ~ "even",
c(1, 3) ~ "odd")
#[1] "odd" "even" "odd" "even" "even" "even"
Upvotes: 5
Reputation: 1349
If you want to replace lot of values in single go, you can use 'library(car)'.
Example
library(car)
x <- rep(1:5,3)
xr <- recode(x, '3=1; 4=2')
x
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
xr
## [1] 1 2 1 2 5 1 2 1 2 5 1 2 1 2 5
Upvotes: 2
Reputation: 5269
Why the fuss?
replace(haystack, haystack %in% needles, replacements)
Demo:
haystack <- c("q", "w", "e", "r", "t", "y")
needles <- c("q", "w")
replacements <- c("a", "z")
replace(haystack, haystack %in% needles, replacements)
#> [1] "a" "z" "e" "r" "t" "y"
Upvotes: 2
Reputation: 1761
To replace more than one number:
vec <- 1:10
replace(vec, vec== c(2,6), c(0,9)) #2 and 6 will be replaced by 0 and 9.
Edit:
for a continous series, you can do this vec <- c(1:10); replace(vec, vec %in% c(2,6), c(0,9))
but for vec <- c(1:10,2,2,2); replace(vec, vec %in% c(2,6), 0)
we can replace multiple values with one value.
Upvotes: 2
Reputation: 193687
Perhaps replace
is what you are looking for:
> x = c(3, 2, 1, 0, 4, 0)
> replace(x, x==0, 1)
[1] 3 2 1 1 4 1
Or, if you don't have x
(any specific reason why not?):
replace(c(3, 2, 1, 0, 4, 0), c(3, 2, 1, 0, 4, 0)==0, 1)
Many people are familiar with gsub
, so you can also try either of the following:
as.numeric(gsub(0, 1, x))
as.numeric(gsub(0, 1, c(3, 2, 1, 0, 4, 0)))
After reading the comments, perhaps with
is an option:
with(data.frame(x = c(3, 2, 1, 0, 4, 0)), replace(x, x == 0, 1))
Upvotes: 89
Reputation: 51680
Another simpler option is to do:
> x = c(1, 1, 2, 4, 5, 2, 1, 3, 2)
> x[x==1] <- 0
> x
[1] 0 0 2 4 5 2 0 3 2
Upvotes: 20