Set values NA from first occurence of Pattern to end

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Set values NA from first occurence of Pattern to end



Is there a faster/ shorter way to set values after and including match to NA ?


vec <- 1:10;vec[c(3,5,7)]<-c(NA,NaN,"remove")
#"1" "2" NA "4" "NaN" "6" "remove" "8" "9" "10"



Desired Outcome:


#"1" "2" NA "4" "NaN" "6" NA NA NA NA



My code:


vec[grep("^remove$",vec)[1]:length(vec)]<-NA



Please note:



In that case, we assume there will be a "remove" element prominent. So the solution does not have to take care of the case that there isn't any.




4 Answers
4



You can use match to stop searching after the first match is found:


match


m = match("remove", vec) - 1L
if (is.na(m))
vec
else
c(head(vec, m), rep(vec[NA_integer_], length(vec)-m))



You'd have to have a pretty large vector to notice a speed difference, though, I guess. Alternately, this might prove faster:


m = match("remove", vec)
if (!is.na(m))
vec[m:length(vec)] <- NA





probably for large vectors your first approach is the CPU fastest.
– Andre Elrico
Aug 6 at 15:13



Not sure if this is shorter or faster but here is one alternative :


vec[which.max(vec == "remove"):length(vec)] <- NA
vec
#[1] "1" "2" NA "4" "NaN" "6" NA NA NA NA



Here , we find the first occurrence of "remove" using which.max and then add NA's till the end of the vector.


which.max


NA



OP has mentioned that there is a "remove" element always present so we need not take care of other case however, in case we still want to keep a check we can add an additional condition.


inds <- vec == "remove"
if (any(inds))
vec[which.max(inds) : length(vec)] <- NA





What about the zero-matches case? I mean vec = "don't remove me!"; vec[which.max(vec == "remove"):length(vec)] <- NA; vec
– Frank
Aug 6 at 15:09


vec = "don't remove me!"; vec[which.max(vec == "remove"):length(vec)] <- NA; vec





This is a nice way to approach it. +1
– Onyambu
Aug 6 at 15:12





@Onyambu nope this wouldn't work if there is no match as Frank illustrated, same goes with your solution.
– zx8754
Aug 6 at 15:14





@zx8754 not even mine would work. Let's assume there is a "remove" element for sure!
– Andre Elrico
Aug 6 at 15:16





@Frank , zx8754 oops sorry, I just assumed there would always be "remove" element but no harm covering all the cases. Thanks :)
– Ronak Shah
Aug 6 at 15:25



We can use cumsum on a logical vector


cumsum


vec[cumsum(vec %in% "remove") > 0] <- NA



We can also just extend the vec to the desired length:


`length<-`(vec[1:(which(vec=="remove")-1)],length(vec))
[1] "1" "2" NA "4" "NaN" "6" NA NA NA NA





changing the "length" property in this situation is ingenious.
– Andre Elrico
Aug 6 at 15:31





This assumes that there is only one match for "remove" (otherwise which will have length greater than 1) and that the match occurs after the first position (since otherwise you'll have vec[1:0] when you should have vec[0]). Could use which(...)[1] and head instead, though, I think.
– Frank
Aug 6 at 15:38


which


which(...)[1]


head





I'll remove mine, it's too similar, I lay it down here though as it was a bit faster on microbenchmark : 'length<-'(vec[seq_len(match("remove",vec)-1)],length(vec)), it matches only the first element but fails if "remove" is not there at all.
– Moody_Mudskipper
Aug 8 at 7:47


microbenchmark


'length<-'(vec[seq_len(match("remove",vec)-1)],length(vec))


"remove"






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

make 2 or more post in bootsrap

Store custom data using WC_Cart add_to_cart() method in Woocommerce 3

Firebase Auth - with Email and Password - Check user already registered