R - Filter a vector using a function
Solution 1
You'll need to Vectorize the function to call it on a vector:
isGoodNumber = Vectorize(isGoodNumber)
v[isGoodNumber(v)]
Solution 2
There is a function named "Filter" that will do exactly what you want:
Filter( isGoodNumber, v)
#[1] 5 5 5 5
There would be the option of making a function that was vectorized, either by by the use of the Vectorize
function (already illustrated) or writing it with ifelse
(also mentioned) and there would be the option of a function that was "Filter"-like
isGoodNumber3 <- function(X)
{ X[ ifelse(X==5, TRUE,FALSE)]
}
isGoodNumber3(v)
#[1] 5 5 5 5
Solution 3
I think here is the easiest method
> v<-c(1,2,3,4,5,5,5,5)
> v[v==5]
[1] 5 5 5 5
Solution 4
Use mapply():
> v <- c(1,2,3,4,5,5,5,5)
> newV <- mapply(function(X) { if (X==5) return(TRUE) else return(FALSE) }, v)
> newV
[1] FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
> v[newV == TRUE]
[1] 5 5 5 5
Solution 5
You should get into the habit of writing vectorised functions where possible. For example, if you're writing a function f(x)
, make sure it works when x
is a vector, not just a single number. Don't rely on Vectorize
to do this for you, because it will be slow for very large vectors.
A useful technique is to replace if ... then ... else
with ifelse
. For example:
isGoodNumber <- function(X)
{
ifelse(X==5, TRUE, FALSE)
}
v<-c(1,2,3,4,5,5,5,5)
v [ isGoodNumber(v) == TRUE ]
In this particular case you can of course streamline things:
isGoodNumber <- function(X) return(X==5)
or even just
v[v==5]
but the ifelse
technique will be useful more generally.
MadSeb
Updated on July 09, 2022Comments
-
MadSeb almost 2 years
I have a function similar to this one:
isGoodNumber <- function(X) { if (X==5) return(TRUE) else return(FALSE) } I have a vector: v<-c(1,2,3,4,5,5,5,5)
I want to obtain a new vector that contains the elements of
v
whereisGoodNumber(v) == TRUE
How do I do this ?
Tried
v [ isGoodNumber(v) == TRUE ]
but it doesn't work :-)Thanks !!
-
Dason over 12 yearsAre you able to rewrite the function? Or is the function defined and you aren't able to change it?
-
Chase over 12 yearsI'm guessing your real application is more complicated than the example, but
v[v==5]
will do the trick for your example. -
MadSeb over 12 yearsHi @Dason, yes I am able to rewrite the function :-)
-
MadSeb over 12 years@Chase : yes, the real application is more complicated than the example :-) but thanks anyway !
-
Dason over 12 yearsI was just asking because ifelse is a vectorized version of if. The fact that you're using if in this example is what causes problems. There are ways to get around functions that can't easily be vectorized but in some situations the best solution is to just write your function in a vectorized way initially.
-
IRTFM almost 3 years@Dason. Just for the record (and I suspect you know this now)
ifelse
in R is NOT a vectorized version ofif
Theif
function is designed to execute code. It WILL execute anything in either its second or third arguments. The executed code may be rather complex and assignments are retained in the calling environment. Theifelse
function will return only a vector of values chosen from between two sets of possible values. Including assignments in the alternatives will NOT be successful. Thinking of them as similar will lead you to erroneous conclusions.
-
-
krlmlr about 10 yearsThis is the only answer that doesn't require repetition of
v
, which is a good thing ifv
is a computed expression. -
Thomas Luechtefeld over 2 yearseasier with pipes
v %>% .[sapply(.,isGoodNumber)]
. the.
references the v object and sapply appliesisGoodNumber
to each element in v. -
IRTFM over 2 years@ThomasLuechtefeld. We must have different definitions of easy. The piped method looks more complicated than ‘v[ sapply(v, isGoodNumber)]’ and they both look less elegant than the Filter method.
-
Thomas Luechtefeld over 2 yearsyou are correct, my mistake.