3
votes

I have a list[] of items from which I'd like to display one randomly, but the displayed item must not repeat more than once in last x requests.

  1. list1 = item1, item2, item3, item4, item5, item6, item7, item8, item9, item 10
  2. Display a random selection from the list above
  3. list2 = store the last displayed item in list2 which should only store 7 items, not more
  4. Display a random selection from the list but make sure it doesn't exist in the list2

Is that the right way to do it? Either way, I'd like to know how to limit a list to store only 7 items?

Thanks

5
Duplicate: stackoverflow.com/questions/1058712/…. Possibly homework.S.Lott

5 Answers

7
votes

collections.deque is the only sequence type in python that naturally supports being bounded (and only in Python 2.6 and up.) If using python 2.6 or newer:

# Setup
from collections import deque
from random import choice
used = deque(maxlen=7)

# Now your sampling bit
item = random.choice([x for x in list1 if x not in used])
used.append(item)

If using python 2.5 or less, you can't use the maxlen argument, and will need to do one more operation to chop off the front of the deque:

while len(used) > 7:
    used.popleft()

This isn't exactly the most efficient method, but it works. If you need speed, and your objects are hashable (most immutable types), consider using a dictionary instead as your "used" list.

Also, if you only need to do this once, the random.shuffle method works too.

4
votes

Is this what you want?

list1 = range(10)
import random
random.shuffle(list1)
list2 = list1[:7]
for item in list2:
    print item
print list1[7]

In other words, look at random.shuffle(). If you want to keep the original list intact, you can copy it: list_copy = list1[:].

2
votes

You could try using a generator function and call .next() whenever you need a new item.

import random
def randomizer(l, x):
    penalty_box = []
    random.shuffle(l)
    while True:
        element = l.pop(0)
        # for show
        print penalty_box, l
        yield element
        penalty_box.append(element)
        if len(penalty_box) > x:
            # penalty time over for the first element in the box
            # reinsert randomly into the list
            element = penalty_box.pop(0)
            i = random.randint(0, len(l))
            l.insert(i, element)

Usage example:

>>> r = randomizer([1,2, 3, 4, 5, 6, 7, 8], 3)
>>> r.next()
[] [1, 5, 2, 6, 4, 8, 7]
3
>>> r.next()
[3] [5, 2, 6, 4, 8, 7]
1
>>> r.next()
[3, 1] [2, 6, 4, 8, 7]
5
>>> r.next()
[3, 1, 5] [6, 4, 8, 7]
2
>>> r.next()
[1, 5, 2] [4, 3, 8, 7]
6
>>> r.next()
[5, 2, 6] [4, 3, 8, 7]
1
>>> r.next()
[2, 6, 1] [5, 3, 8, 7]
4
>>> r.next()
[6, 1, 4] [3, 8, 2, 7]
5
1
votes

Something like:

# Setup
import random
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list2 = []

# Loop for as long as you want to display items
while loopCondition:
    index = random.randint(0, len(list1)-1)
    item = list1.pop(index)

    print item

    list2.append(item)
    if(len(list2) > 7):
        list1.append(list2.pop(0))
1
votes

I'd use set objects to get a list of items in list1 but not in list2:

import random

list1 = set(["item1", "item2", "item3", "item4", "item5",
             "item6", "item7", "item8", "item9", "item10"])
list2 = []
while True:  # Or something
    selection = random.choice(tuple(list1.difference(set(list2))))
    print(selection)
    list2.append(selection)
    if len(list2) > 7:
        list2 = list2[-7:]