All pastes #425258 Raw Edit

Someone

public python v1 · immutable
·published 2007-04-05 11:43 UTC
rendered paste body
    def sample(self, population, k):        """Chooses k unique random elements from a population sequence.        Returns a new list containing elements from the population while        leaving the original population unchanged.  The resulting list is        in selection order so that all sub-slices will also be valid random        samples.  This allows raffle winners (the sample) to be partitioned        into grand prize and second place winners (the subslices).        Members of the population need not be hashable or unique.  If the        population contains repeats, then each occurrence is a possible        selection in the sample.        To choose a sample in a range of integers, use xrange as an argument.        This is especially fast and space efficient for sampling from a        large population:   sample(xrange(10000000), 60)        """        # XXX Although the documentation says `population` is "a sequence",        # XXX attempts are made to cater to any iterable with a __len__        # XXX method.  This has had mixed success.  Examples from both        # XXX sides:  sets work fine, and should become officially supported;        # XXX dicts are much harder, and have failed in various subtle        # XXX ways across attempts.  Support for mapping types should probably        # XXX be dropped (and users should pass mapping.keys() or .values()        # XXX explicitly).        # Sampling without replacement entails tracking either potential        # selections (the pool) in a list or previous selections in a set.        # When the number of selections is small compared to the        # population, then tracking selections is efficient, requiring        # only a small set and an occasional reselection.  For        # a larger number of selections, the pool tracking method is        # preferred since the list takes less space than the        # set and it doesn't suffer from frequent reselections.        n = len(population)        if not 0 <= k <= n:            raise ValueError, "sample larger than population"        random = self.random        _int = int        result = [None] * k        setsize = 21        # size of a small set minus size of an empty list        if k > 5:            setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets        if n <= setsize or hasattr(population, "keys"):            # An n-length list is smaller than a k-length set, or this is a            # mapping type so the other algorithm wouldn't work.            pool = list(population)            for i in xrange(k):         # invariant:  non-selected at [0,n-i)                j = _int(random() * (n-i))                result[i] = pool[j]                pool[j] = pool[n-i-1]   # move non-selected item into vacancy        else:            try:                selected = set()                selected_add = selected.add                for i in xrange(k):                    j = _int(random() * n)                    while j in selected:                        j = _int(random() * n)                    selected_add(j)                    result[i] = population[j]            except (TypeError, KeyError):   # handle (at least) sets                if isinstance(population, list):                    raise                return self.sample(tuple(population), k)        return result