How can I generate an array of 8 unique numbers in python? - python

I'm trying to create a function that, one by one, generates 8 random numbers from 1 to 8 and adds them to an array, checking if they are unique each time before adding them. However, it doesn't work as expected and, while it creates an array consisting of 8 elements, the numbers are not all unique. My code:
import random #Allows the program to generate random numbers
correctSequence = [] #Defines array
def generateSequence(correctSequence): #Defines function, passes array as parameter
selection = random.randint(1,8) #Creates a random number and adds it to the array so there is a starting point for the for loop (Ln 10)
correctSequence.append(str(selection))
while len(correctSequence) < 8: #The while loop will continue to run until the array consists of 8 objects
selection = random.randint(1,8) #Generates a random number
for i in range(len(correctSequence)): #Loops through each value in the array
if correctSequence[i] == selection: #This line checks to see if the value already exists in the array
print("Duplicate") #This line is meant to print "Duplicate" when a duplicate value is generated
else:
correctSequence.append(str(selection)) #If the value doesnt already exist in the array, it will be added
print("Valid") #This line is meant to print "Valid" when a unique value is generated and added to the array
return correctSequence
#Main body of program
generateSequence(correctSequence) #The function is called
print(correctSequence) #The array is printed
I think the problem occurs somewhere around line 10 as the program seems to go straight to the else statement but I can't see why this would happen.
Additionally, when I run the program, the array, when printed, always seems to repeat the same 2 or 3 numbers multiple times, I don't know if this relates to the already existing issue but it could help to explain what's going on.

8 random numbers from 1 to 8 and adds them to an array, checking if they are unique each time before adding them
There is nothing "random" here. All you need to do is to shuffle the numbers 1 to 8.
import random
nums = list(range(1, 9))
random.shuffle(nums)
print(nums)
# [2, 6, 4, 3, 1, 7, 8, 5]

For the way you want to do it:
import random #Allows the program to generate random numbers
correctSequence = [] #Defines array
def generateSequence(correctSequence): #Defines function, passes array as parameter
while len(correctSequence) < 8:
selection = random.randint(1,8) #Creates a random number and adds it to the array so there is a starting point for the for loop (Ln 10)
correctSequence.append(selection) if selection not in correctSequence else None
return correctSequence
generateSequence(correctSequence) #The function is called
print(correctSequence) #The array is printed
But there are better ways for example:
import random #Allows the program to generate random numbers
def generateSequence():
return random.sample([1,2,3,4,5,6,7,8], 8)
print(generateSequence())
or change the return to return random.sample(range(1, 9), 8) as mentioned above for extra conciseness.

Related

Random populations of empty lists

I have to write a program in Python in which I give a range and a number of selections to append for 2 empty lists, so the approach of this program should be like this:
Give range to select from: 10
Give number of selections: 5
I should get:
List of numbers selected randomly: [2,3,7,1,8]
List of numbers not selected: [4,6,5,9,10]
Numbers should not be repeated nor exist in both lists
I have this code:
import random
selected_list=[]
not_selected=[]
selecting_number=int(input('give range to select from : '))
select_num=int(input('give number of selections: '))
if selecting_number<select_num:
print('error')
elif selecting_number>=select_num:
for x in range(select_num):
selected_list.append(random.randint(1,select_num))
print(f'List of numbers selected randomly: {selected_list}')
if not_selected not in selected_list:
for y in range(select_num):
not_selected.append(random.randint(1,select_num))
print(f'List of numbers not selected previously: {not_selected}')
This is the output
List of numbers selected randomly: [6, 7, 7, 7, 7]
List of numbers not selected: [2, 4, 4, 8, 5]
What is causing the error is that random is picking random numbers independently and because they are random sometimes the same number is getting picked multiple times.
To fix this, you can use random.sample(the_list_to_pick_from, number_to_pick)
From the docs:
Returns a list of unique elements chosen from the population sequence
or set. Used for random sampling without replacement.
One implementation is this:
import random
range_to_pick_from = list(range(1,10))
selected = random.sample(x, 5)
not_selected = [a for a in range_to_pick_from if a not in selected]
print(selected,not_selected)
not_selected can also be written as a traditional for loop:
not_selected = []
for num in range_to_pick_from:
if num not in selected:
not_selected.append(num)
Documentation for random.sample
You could create a function to replicate this often and take in your parameters.
import random
def make_random_lists(my_range=10, selections=5):
"""
Generate two lists of random numbers.
INPUT
------
my_range - (int) how large the range we are selecting from
selections - (int) how many numbers should be in the list select list
OUTPUT
------
s - (list) the selected numbers
ns - (list) not selected numbers
"""
# make sure input values are valid
if (selections < my_range):
return "selections must be less than range", None
if my_range <= 0:
return "range must be larger than 0", None
total_numbers = set(range(1, my_range+1)) # make range
s = random.sample(total_numbers, k=selections) # get selections
ns = total_numbers - set(s) # find those not used
return s, list(ns)
You do not need to set a seed unless you want to replicate your results with each run. Using sets to update your list is just another way to implement what is being done here! you could even combine the lines to make this more concise but this helps make it pretty clear.
Calling this function will yield the following results:
selected, not_selc = make_random_lists(12, 4)
print(selected)
print(not_selc)
>>>[7, 5, 3, 4]
>>>[1, 2, 6, 8, 9, 10, 11, 12]
Documentation
sets
random
modules/functions
Pyhton3 tutorial

Range(5) is returning 4 or 5 random integers

I've created a program to generate 5 random integers from 1-10 and add them to an empty set. For some reason, when I run the program, it will sometimes return 4 integers, and other times 5. What is happening here?
import random
set1 = set()
for x in range(5):
integer = random.randint(1,10)
set1.add(integer)
print(set1)
You're using a set, sets can't contain duplicates, if the same number is generated twice it will only occur in the set once, theoretically its possible your output would only have 1 number in it (if the same number was added 5 times).
You should use a list instead:
import random
output = []
for x in range(5):
integer = random.randint(1,10)
output += [integer]
print(output)
The easiest way to generate n random unique numbers is to use random.sample:
>>> import random
>>> set(random.sample(range(1, 11), 5))
set([8, 9, 5, 6, 10])
Note that you should use range(1, 11) if you also want to include the number 10.
Python sets will not show duplication. A simple way to fix your script is to use a list instead of a set. One thing to note however, is if you are going to want to use all the numbers together like 12345, this won't do the trick. The following script will return a list as [1, 2, 3, 4, 5].
list1 = [] # Make an empty list
for x in range(5):
# randomly choose a number from 1 - 10 and append it to our list 5 times
integer = random.randint(1,10)
list1.append(integer)
print(list1) # print the list

Generate list of 5 non-repeating integers

I'm new to Python and I am trying to generate a list of 4 random numbers with integers between 1 and 9. The list must contain no repeating integers.
The issue I am having is that the program doesn't output exactly 4 numbers everytime. Sometimes it generates 3 numbers or 2 numbers and I can't figure out how to fix it.
My code:
import random
lst = []
for i in range(5):
r = random.randint(1,9)
if r not in lst: lst.append(r)
print(lst)
Is there a way to do it without the random.sample? This code is part of a larger assignment for school and my teacher doesn't want us using the random.sample or random.shuffle functions.
Your code generates 5 random numbers, but they are not necessarily unique. If a 2 is generated and you already have 2 in list you don't append it, while you should really be generating an alternative digit that hasn't been used yet.
You could use a while loop to test if you already have enough numbers:
result = [] # best not to use list as a variable name!
while len(result) < 5:
digit = random.randint(1, 9)
if digit not in result:
result.append(digit)
but that's all more work than really needed, and could in theory take forever (as millions of repeats of the same 4 initial numbers is still considered random). The standard library has a better method for just this task.
Instead, you can use random.sample() to take 5 unique numbers from a range() object:
result = random.sample(range(1, 10), 5)
This is guaranteed to produce 5 values taken from the range, without duplicate digits, and it does so in 5 steps.
Use random.sample:
import random
random.sample(range(1, 10), 4)
This generates a list of four random values between 1 to 9 with no duplicates.
Your issue is, you're iterating 5 times, with a random range of 1-9. That means you have somewhere in the neighborhood of a 50/50 chance of getting a repeat integer, which your conditional prevents from being appended to your list.
This will serve you better:
def newRunLst():
lst = []
while len(lst) < 4:
r = random.randint(1,9)
if r not in lst: lst.append(r)
print lst
if random list needed is not too small (compared to the total list) then can
generate an indexed DataFrame of random numbers
sort it and
select from the top ... like
(pd.DataFrame([(i,np.random.rand()) for i in range(10)]).sort_values(by=1))[0][:5].sort_index()

Unwanted random iterator in For-Loop

I tried to create a function for generating a set number (numbersToChoose) of values between two other values (startFrom and stopAt) but for some reason the iterator (?) in the second for-loop (line 7), in this case a seems to be randomly generated even though I don't see any reason for that.
def chooseRandomNumbers(numbersToChoose, startFrom, stopAt):
numbers = [(randrange(startFrom, stopAt))] # initialize empty list of numbers
for n in range(numbersToChoose-1): # choose random number from 1 to 49 a total of 7 times
x = randrange(startFrom, stopAt+1)
for a in numbers: # check for already existing elements in "numbers"
if x == numbers[a]: # if new random number already exists in "numbers" discard and run loop again
n -= 1 # decreases n by 1 so a new (hopefully not already existing) number can be generated
else: # generated numbers does not exist in "numbers" yet
numbers.append(x) # appends randomly chosen number to list "numbers"
return numbers # returns said list "numbers"
Any advice on how to deal with this is greatly appreciated.
Also please tell me if possible anything else bad in the code (just started python).
Your code to check if generated number is already in the list is wrong.
for a in numbers, in this loop, you are using numbers[a] while a is a member of list but not the index of the member.
use in to test if a number is in list:
from random import randrange
def chooseRandomNumbers(numbersToChoose, startFrom, stopAt):
numbers = []
for n in range(numbersToChoose):
x = randrange(startFrom, stopAt+1)
if not x in numbers:
numbers.append(x)
else:
n -= 1
return numbers
or simply:
from random import sample
def chooseRandomNumbers(numbersToChoose, startFrom, stopAt):
return sample(range(startFrom,stopAt+1),numbersToChoose)

Random sampling from a set of integers

I am working with python 3.2 and I spent a lot of time trouble shooting this, and I still can't seem to wrap my brain around it.
number = random.randint ( x0 ,xn )
I'm generating a random number. It's purpose is to make my code come at me differently everytime.
For example I have 10 variables of text that I have written. I have solved the problem of not having these variables appear in the same order at each program run.
The issue I have is that they now appear randomly everytime. It picks one out of 10 everytime, instead the first time 10 and next 9. I can't seem to find out how to exclude the previous ones.
thelist = [0]
while i < x
if number in thelist:
>>>repeat<<<
else:
thelist.append (number)
if ( number == x0 ):
>>>something<<<
elif ( number == x1 ):
>>>something<<<
This is what I would imagine the code would look like, everytime you loop one more number gets appended to the list, so that everytime it picks a number already in the list it repeats the loop again until it then has used all the numbers that random.randint can pull.
Here's a shuffle function:
import random
max = 15
x = list(range(max+1))
for i in range(max, 0, -1):
n = random.randint(0, i)
x[n], x[i] = x[i], x[n]
This starts with a sorted list of numbers [0, 1, ... max].
Then, it chooses a number from index 0 to index max, and swaps it with index max.
Then, it chooses a number from index 0 to index max-1, and swaps it with index max-1.
And so on, for max-2, max-3, ... 1
As yosukesabai rightly notes, this has the same effect as calling random.sample(range(max+1), max+1). This picks max + 1 unique random values from range(max+1). In other words, it just shuffles the order around. Docs: http://docs.python.org/2/library/random.html#random.sample
If you wanted something more along the lines of your proposed algorithm, you could do:
import random
max = 15
x = range(max+1)
l = []
for _ in range(max+1):
n = random.randint(0,max)
while n in l:
n = random.randint(0,max)
l.append(n)
From what I understand of your description and sample code, you want thelist to end up with every integer between x0 and xn in a random order. If so, you can achieve that very simply with random.shuffle(), which shuffles a list in place:
import random
x0 = 5
xn = 15
full_range = list(range(x0, xn))
print(full_range)
random.shuffle(full_range)
print(full_range)

Categories

Resources