On Fri, 10 Jul 2020 at 06:56, Chris Angelico <ros...@gmail.com> wrote:
>
> On Fri, Jul 10, 2020 at 3:41 PM Inada Naoki <songofaca...@gmail.com> wrote:
> >
> > On Fri, Jul 10, 2020 at 1:53 PM Chris Angelico <ros...@gmail.com> wrote:
> > >
> > >
> > > And immediately above that part, I said that I had made use of this,
> > > and had used it in Python by listifying the dict first. Okay, so I
> > > didn't actually dig up the code where I'd done this, but that's a use
> > > case. I have *actually done this*. In both languages.
> > >
> >
> > Do you pick random item repeatedly from same dictionary?
> > If so, you can create a list once in Python.
> >
>
> I would pick repeatedly from the same dictionary but it might be
> mutated in between. So the list would have to be reconstructed fresh
> every time.

Maybe there could be a function in the random module for making a
random choice from an arbitrary (finite) iterable:

# rnd.py
from random import randrange

def choice_iter(iterable):
    iterator = iter(iterable)
    try:
        value = next(iterator)
    except StopIteration:
        raise ValueError("Empty iterable")
    for n, candidate in enumerate(iterator, 2):
        if not randrange(n):
            value = candidate
    return value

You could use that to get a choice from a dict, set etc. For a large
dict/set it will be slow compared to converting to a list because it's
calling randrange once per item. If you have a good reason not to
build the list though then you could use it. For example to get a
random line from a possibly large text file:

>>> from rnd import choice_iter
>>> with open('rnd.py') as fin:
...     line = choice_iter(fin)
...
>>> line
'    except StopIteration:\n'

It's not hard to generalise the function above to something that e.g.
makes a selection of k values from the iterable in a single pass. Here
is a version that works without replacement:

def sample_iter(population, k):
    iterator = iter(population)
    values = []
    for _ in range(k):
        try:
            value = next(iterator)
        except StopIteration:
            raise ValueError("Too few items")
        values.append(value)
    for n, candidate in enumerate(iterator, k+1):
        random_index = randrange(n)
        if random_index < k:
            values[random_index] = candidate
    return values  # maybe shuffle first?

--
Oscar
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HKPSBX7FJ7MLQ4TUEBWMJ66YOQVVCT63/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to