I saw a YouTube short demonstrating how to use filter()
in Python along the lines of
nums=range(1,30)
def is_prime(num):
for x in range(2,num):
if (num%x) == 0:
return False
return True
primes=list(filter(is_prime, nums))
print(primes)
# [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
and as always, I like to think about how I’d do this in other languages (e.g. R).
The (deliberately brute-force) is_prime()
function translates easily enough
is_prime <- function(x) {
if (x %in% 1:2) return(TRUE)
for (i in 2:(x-1)) {
if (x %% i == 0) return(FALSE)
}
TRUE
}
and the most common way to run this over a vector of inputs is with something like sapply()
returning a vector of logicals that can be used for square-bracket subsetting
x <- 1:30
primes <- x[sapply(x, is_prime)]
primes
[1] 1 2 3 5 7 11 13 17 19 23 29
We can get rid of the need for sapply()
by vectorising the function which is done easily with Vectorize()
is_prime_v <- Vectorize(is_prime)
primes <- x[is_prime_v(x)]
primes
[1] 1 2 3 5 7 11 13 17 19 23 29
It’s usually at this point that I feel bad about having to write x
twice and lament that while {dplyr} is great for data.frame
s, we don’t have something equivalent for filtering of vectors so easily… except we do (as I usually end up remembering). Filter()
is a base function that works on vectors and is the equivalent of what we saw in Python (per the docs, “Filter corresponds to filter in Haskell”)
primes <- Filter(is_prime, x)
primes
[1] 1 2 3 5 7 11 13 17 19 23 29
In fairness, Filter()
expands to much the same as the above
Filter
function (f, x)
{
f <- match.fun(f)
ind <- as.logical(unlist(lapply(x, f)))
x[which(ind)]
}
<bytecode: 0x12a9db8b0>
<environment: namespace:base>
but it’s a nice interface.
I need to remember to use that (as well as the rest of the gold-mine in the ‘funprog’ toolbox like Map
and Reduce
) more often.