Rosa
Rosa

Reputation: 1833

r How to change vector values?

How do I change 3 values as a set in a vector, eg:

v=c(1,1,1,1,1,6,2,3,4,4,4,4,4,2)
r=v[which(v %in% c(6,2,3))] = c(6,0,8) 
r
[1] 1 1 1 1 1 6 0 8 4 4 4 4 4 6

The result comes with a warning: number of items to replace is not a multiple of replacement length.

The idea result I need is :

[1] 1 1 1 1 1 6 0 8 4 4 4 4 4 2 

I only want the 3 values to change when they are as a set/group, not individually, any suggestion would be great appreciated!

Edit: I'm Sorry guys, actually there are more than one set of 6,2,3 in my data, the example should be look like:

v=c(1,1,2,1,1,6,2,3,4,4,4,4,4,2,6,2,3,4)

And the result be:

[1] 1 1 2 1 1 6 0 8 4 4 4 4 4 2 6 0 8 4

Upvotes: 0

Views: 411

Answers (3)

Sven Hohenstein
Sven Hohenstein

Reputation: 81743

A quite different way using regular expressions:

as.numeric(strsplit(gsub("6 2 3", "6 2 8", paste(v, collapse = " ")), " ")[[1]])
# [1] 1 1 1 1 1 6 2 8 4 4 4 4 4 2

This will replace all instances of c(6, 2, 3).

Upvotes: 1

thelatemail
thelatemail

Reputation: 93938

Base R function using rle

seqrepl <- function(v,find,repl) {
  l <- length(find)
  rv <- rle(v %in% find)
  start <- cumsum(rv$lengths)[which(rv$lengths==l & rv$values==TRUE)-1]+1
  v[start:(start+(l-1))] <- repl
  v
}

Result:

seqrepl(v=v,find=c(6,2,3),repl=c(6,0,8))
#[1] 1 1 1 1 1 6 0 8 4 4 4 4 4 2

An alternative using embed:

seqrepl2 <- function(v,find,repl) {
  l <- length(find)
  start <- which(colSums(t(embed(v,l)) == rev(find)) == l)
  v[start:(start+(l-1))] <- repl
  v
}

seqrepl2(v=v,find=c(6,2,3),repl=c(6,0,8))
#[1] 1 1 1 1 1 6 0 8 4 4 4 4 4 2

Upvotes: 1

Justin
Justin

Reputation: 43265

You can use rollapply from the zoo package:

rollapply(v, width=3, function(x) all(x == c(6, 2, 3)))
# [1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE

And then you can use that boolean to replace the values you want:

s <- which(rollapply(v, width=3, function(x) all(x == c(6, 2, 3))))

v[s:(s+2)] <- c(6, 0, 8)

In one happy function:

rolling_replace <- function(v, p, r) {
  l <- length(r)
  s <- which(rollapply(v, width=l, function(x) all(x == p))) 
  v[s:(s+l-1)] <- r

  return (v)
}

Upvotes: 4

Related Questions