fastest method to choose a random element
Paddy
paddy3118 at googlemail.com
Mon Jan 7 03:04:53 EST 2008
On Jan 5, 6:37 am, Paddy <paddy3... at googlemail.com> wrote:
> On Jan 4, 7:55 pm, c... at mailinator.com wrote:
>
>
>
> > Hello,
> > This is a question for the best method (in terms of performance
> > only) to choose a random element from a list among those that satisfy
> > a certain property.
>
> > This is the setting: I need to pick from a list a random element
> > that satisfies a given property. All or none of the elements may have
> > the property. Most of the time, many of the elements will satisfy the
> > property, and the property is a bit expensive to evaluate. Chance of
> > having the property are uniform among elements.
>
> > A simple approach is:
>
> > import random
> > def random_pick(a_list,property):
> > '''Returns a random element from a list that has the property
>
> > Returns None if no element has the property
> > '''
> > random.shuffle(a_list)
> > for i in a_list:
> > if property(i): return i
>
> > but that requires to shuffle the list every time.
>
> > A second approach, that works if we know that at least one element of
> > the list has the property, is:
>
> > import random
> > def random_pick(a_list,property):
> > '''Returns a random element from a list that has the property
>
> > Loops forever if no element has the property
> > '''
> > while 1:
> > i=random.choice(a_list)
> > if property(i): return i
>
> > which is more efficient (on average) if many elements of the list have
> > the property and less efficient if only few elements of the list has
> > the property (and goes crazy if no element has the property)
>
> > Yet another one:
>
> > import random
> > def random_pick(a_list,property):
> > '''Returns a random element from a list that has the property
> > '''
> > b_list=[x for x in a_list if property(x)]
> > try:
> > return random.choice(b_list)
> > finally: return None
>
> > but this one checks the property on all the elements, which is no
> > good.
>
> > I don't need strong random numbers, so a simple solution like:
> > import random
> > globalRNG=random.Random()
>
> > def random_pick(a_list,property):
> > '''Returns a random element from a list that has the property
>
> > Works only if len(a_list)+1 is prime: uses Fermat's little theorem
> > '''
> > a=globalRNG(1,len(a_list))
> > ind=a
> > for i in xrange(len(a_list)):
> > x=a_list[a-1]
> > if property(x):return x
> > ind*=a
>
> > but this works only if len(a_list)+1 is prime!!! Now this one could be
> > saved if there were an efficient method to find a prime number given
> > than a number n but not very much greater...
>
> > Any other ideas? Thanks everybody
>
> Caching might help.
>
> If random_pick is called several times with the same list(s) then
> cache the result of
> [property(i) for i in a_list] against a_list.
>
> If random_pick is called several times with list(s) whith multiple
> instances of list items then cache
> property(i) against i for i in a_list .
>
> You could do both.
>
> You might investigate wether property(i) could be implemented using a
> faster algorithm, maybe table lookup, or interpolation from initial
> table lookup.
>
> - Paddy.
Here's a caching decorator that you could apply to function property:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498245
- Paddy.
More information about the Python-list
mailing list