How to have my program list every item off of a list randomly and only once

Viewed 164

I'm trying to have a function that uses the random import to randomly select a value from the list [0, 1, 2, 3, 4, 5, 6, 7, 8], print that value, then repeat itself until all the numbers are selected. The problem I'm having is then making sure when it repeats itself it won't choose that number again. What I've tried is:

def ListArranger():
    randomPick = random.choices(list)
    if len(list) > 0:
        if list[randomPick] != " ":
            print(list[randomPick])
            list[randomPick] = " "
            ListArranger()
        else:
            ListArranger()

I run into the problem that says list indices must be integers or slices, not list. I'm assuming it's having a problem because I'm trying to set the list value to a string, but I can't figure out how to work around this

7 Answers

The obvious choice that nobody seems to mention is random.sample:

def ListArranger(lst):
    return random.sample(lst, len(lst))

for pick in ListArranger(range(9)):
    print(pick)

4
0
8
1
2
3
7
6
5

Here is the solution:

import random

def ListArranger(list):
    if len(list) > 0:
        randomPick = random.choice(list)
        print(randomPick)
        list.remove(randomPick)
        ListArranger(list)

list = [0,1,2,3,4,5,6,7,8]
ListArranger(list)

Output:

2
8
7
1
3
4
0
5
6

This function takes a list as an argument an calls itself until the list is empty.

It removes a random element of the list in each recursive call while printing out the removed element.

The error comes from line lines 3,4,5

Because you are indexing your list with a list in all those lines. randomPick is a list not an integer or a slice that's what the error indicates.

Example: print(randomPick[ **[1,2,3,4]** ] here is the actual problem.

You can only index a list by an integer or a slice.

Solution:

import random

lst = [1,2,3,4,5,6,7,8]
check_lst = []

while True:
    random_num = random.choice(lst)
    
    if random_num in check_lst:
        continue
    elif random_num not in check_lst:
        check_lst.append(random_num)
        print(random_num)
    
    if len(lst) == len(check_lst):
        print("Finish the loop")
        break

You can shuffle() copy (quote from docs: "All slice operations return a new list containing the requested elements.") of given list once and yield from (PEP 380) shuffled list from generator function.

from random import shuffle

def ListArranger(lst):
    lst_copy = lst[:]
    shuffle(lst_copy)

    yield from lst_copy

You can iterate over this function which will return you every time new random element from lst.

If you don't need to keep source list untouched, you can omit copying, shuffle list itself and iterate over it.

import random
lst=[0,1,2,3,4,5,6,7,8]
lstlen=len(lst)
def ListArranger():
    if len(lst)!=0:
        randomPick=random.choice(lst)
        print(randomPick)
        lst.pop(lst.index(randomPick))
        ListArranger()
    else:
        for i in range(lstlen):
            lst.append(" ")
            
ListArranger()

If you think of your list as a stack, you can just shuffle() once and then pop() each element off in-sequence until you are done.

Also, this is a chance to use a generator. You can turn any function into a generator simply by adding a yield <something>. Then you can use it in a for statement.

Our input list remains intact because we internally copy() it.

from random import shuffle

def chooseOneWithoutReplace(items):
    data = items.copy()
    shuffle(data)
    while data:
        yield data.pop()
    # nothing more to yield
    # generator ends -> outer for loop ends

daysOfWeek = [1,2,3,4,5,6,7]
for i in chooseOneWithoutReplace(daysOfWeek):
    print(i)

Output

1
4
5
3
7
2
6

Use shuffle, which does just that with a given sequence.

def listArranger(a):
    random.shuffle(a)
    for item in a:
        print(item)

Do not shadow a built-in name with a local variable: list is perhaps the most common bad variable name.

Pass your list into the function, rather than making it an assumption of the outer scope.

Related