For some strange reason, let’s say that I want use List Comprehensions — and List Comprehensions only — to generate 10 random numbers larger than 0.5. For the “10 random numbers” part of the problem we would use:
samples = [ random.random() for x in range(10) ]
Now, for the “larger than 0.5”, how one would implement using LC?
samples = [ random.random() for x in range(10) if ??? ]
What are you describing is called rejection sampling, and is a bad idea. For example if you wanted only numbers
>0.999, it would take 1000 times longer to generate them.Best way
The correct way to do this is to use another sampling technique, such as using the inverse of the CDF (cumulative density function), and doing
[inverseCDF(random()) for _ in range(10)]. In your case, this would be, like GaretJax suggests,[0.5+random()/2 for _ in range(10)]Intent
I think your intent was being able to further filter based on the entire expression of a list comprehension. In that case, you would put your iterable (here with parentheses rathern than […] for laziness, though it doesn’t matter) inside another comprehension:
For a better solution along these lines that can handle rejection, see the “Solution with list comprehensions only” section or eryksun’s answer.
Solution with generators
(see below for a list-comprehension only solution)
You can do this for any linear range. If your rejection function is arbitrarily complex however, a general way to do rejection sampling would be as follows. (Again, a very bad idea unless you know what you’re doing and efficiency doesn’t matter.)
Example:
You could also do something like:
Solution with list comprehensions only
However since you want to use list comprehensions only, this means the expression-part of your comprehension cannot fail, so you have to somehow embed a while loop in the comprehension. This is impossible to do with a single lambda function alone, but we can pull it off as long as we have some recursive/loopy primitive, for example…
(If you really wanted a one-liner list comprehension,
randoms()can be rewritten as(random() for _ in count()).) Again, this is unnecessary if you easily find the analytic inverse cumulative distribution function for your particular distribution.edit: I take that back… it… is possible… with just lambdas…
DEAR GOD HAVE MERCY WHAT HORRORS HAVE I UNLEASHED UPON THE WORLD NOOOOOO