[Tutor] Need help understanding output...

Steven D'Aprano steve at pearwood.info
Wed Aug 18 23:24:24 CEST 2010

On Wed, 18 Aug 2010 09:21:51 pm Laurens Vets wrote:
> On 8/12/2010 1:26 AM, Steven D'Aprano wrote:
> > On Thu, 12 Aug 2010 07:04:15 am Laurens Vets wrote:
> >> I need to generate a list of 30 numbers randomly chosen from 1, 2,
> >> 3, 4, 5&  6. However, I cannot have more than 2 numbers which are
> >> the same next to each other.
> Thank you all for your help! I've added another condition to this
> program, namely, in a range of 60, each 'random' number can only
> occur 10 times. I came up with the following:

The more of these restrictions you add, the less random the sequence is. 
A truly random (that is, uniformly random) sequence should come up with 
30 identical numbers occasionally. *Very* occasionally, to be sure, but 
it still should be possible.

If what you need is a sequence of numbers which is only slightly random, 
then that's fine. But I don't fully understand what your aim is here.

Anyway, here's my take on generating 30 semi-random integers from 1 to 6 
where there are no more than 10 of each number and no more than two in 
a row of anything.

Completely untested:

def make_counts(total=30):
    counts = {}
    t = total
    for i in range(1, 7):
        n = random.randint(0, min(t, 10))
        counts[i] = n
        t -= n
    assert sum(counts.values) == total  # Is this guaranteed?
    return counts

def make_seq():
    result = []
    counts = make_counts(30)
    for i in range(30):
        t = random.choose(counts.keys())
        while [t] != result[-2:]
            if len(counts) == 1 and counts.keys() == result[-2:]:
                # Stuck!
                raise ValueError
            t = random.choose(counts.keys())
        counts[t] -= 1
        if counts[t] == 0:
            del counts[t]
    return result

I'm a bit dubious about the assertion in make_counts... I think I need 
to be a bit more clever about generating the counts to guarantee that 
there will be exactly 30 in total. At the moment it only guarantees no 
more than 30.

Note also the test inside the while loop in make_seq. Given your 
additional restriction, it might happen that you have a sequence like 
[blah blah... 3, 3] and 3 is the only remaining key in count. In that 
case, the while loop will never terminate.

Another alternative is not to try to be clever at all. Instead, use a 
nice simple rejection method:

* generate a list of thirty random numbers
* reject it if it has 3 numbers in a row, or more than 10 of any number
* if rejected, start again with a new random list

Steven D'Aprano

More information about the Tutor mailing list