Random populations of empty lists - python

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

Related

How can I generate an array of 8 unique numbers in 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.

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

How to remove duplicate number within a list and then replace with a new random number

new to python. I'm trying to make a lottery-styled thing, where the for loop appends 5 random numbers into a list.
Let's say the list so far is nList = [1,2,3,4] and the last iteration happens to also be a 4.
I want the code to remove the extra 4 that was supposed to be in the last index, and replace it with a brand new random number that does NOT duplicate any of the rest of the numbers on the list. I can't seem to wrap my head around it.
I've tried using nList.pop(), and that solves the problem of removing the duplicate, I just don't know how to add the new random number.
import random
nList = []
random.seed()
for x in range(5):
n = random.randint(1,39)
for item in nList:
if n == item:
nList.pop()
else:
nList.append(n)
print(nList)
I just end up with a smaller list, which is not what I want.
Instead of using a list you can use a set which has the special property of having no duplicates. The idea is that if you generate a number that is already inside the set, you simply reroll until you get a number that is not in the set. By using a set, you also have the advantage of having O(1) lookup time.
import random
nList = set()
for x in range(5):
n = random.randint(1,39)
while n in nList:
n = random.randint(1,39)
nList.add(n)
print(list(nList))
Example Output
[24, 25, 11, 12, 15]
Actually you can do it in a way easier way, using directly do this from random module (No need to go the hard way and reinvent the wheel - except for learning purpose):
import random
print(random.sample(range(1,39),5))
Example of output:
[29, 20, 26, 17, 37]
Explanations:
range(1,39) to generate the range you need (i.e. your initial population)
random.sample() Return a k length list of unique elements chosen from the population sequence.

Evenly distribute within a list (Google Foobar: Maximum Equality)

This question comes from Google Foobar, and my code passes all but the last test, with the input/output hidden.
The prompt
In other words, choose two elements of the array, x[i] and x[j]
(i distinct from j) and simultaneously increment x[i] by 1 and decrement
x[j] by 1. Your goal is to get as many elements of the array to have
equal value as you can.
For example, if the array was [1,4,1] you could perform the operations
as follows:
Send a rabbit from the 1st car to the 0th: increment x[0], decrement
x[1], resulting in [2,3,1] Send a rabbit from the 1st car to the 2nd:
increment x[2], decrement x[1], resulting in [2,2,2].
All the elements are of the array are equal now, and you've got a
strategy to report back to Beta Rabbit!
Note that if the array was [1,2], the maximum possible number of equal
elements we could get is 1, as the cars could never have the same
number of rabbits in them.
Write a function answer(x), which takes the array of integers x and
returns the maximum number of equal array elements that we can get, by
doing the above described command as many times as needed.
The number of cars in the train (elements in x) will be at least 2,
and no more than 100. The number of rabbits that want to share a car
(each element of x) will be an integer in the range [0, 1000000].
My code
from collections import Counter
def most_common(lst):
data = Counter(lst)
return data.most_common(1)[0][1]
def answer(x):
"""The goal is to take all of the rabbits in list x and distribute
them equally across the original list elements."""
total = sum(x)
length = len(x)
# Find out how many are left over when distributing niavely.
div, mod = divmod(total, length)
# Because of the variable size of the list, the remainder
# might be greater than the length of the list.
# I just realized this is unnecessary.
while mod > length:
div += length
mod -= length
# Create a new list the size of x with the base number of rabbits.
result = [div] * length
# Distribute the leftovers from earlier across the list.
for i in xrange(mod):
result[i] += 1
# Return the most common element.
return most_common(result)
It runs well under my own testing purposes, handling one million tries in ten or so seconds. But it fails under an unknown input.
Have I missed something obvious, or did I make an assumption I shouldn't have?
Sorry, but your code doesn't work in my testing. I fed it [0, 0, 0, 0, 22] and got back a list of [5, 5, 4, 4, 4] for an answer of 3; the maximum would be 4 identical cars, with the original input being one such example. [4, 4, 4, 4, 6] would be another. I suspect that's your problem, and that there are quite a few other such examples in the data base.
For N cars, the maximum would be either N (if the rabbit population is divisible by the number of cars) or N-1. This seems so simple that I fear I'm missing a restriction in the problem. It didn't ask for a balanced population, just as many car populations as possible should be equal. In short:
def answer(census):
size = len(census)
return size if sum(census) % size == 0 else (size-1)

dict does not contain the expected number of items

I'm writing a program to iterate through a long number, converting it into a string, and then using an index list to pick out 10 individual consecutive numbers from the long number, then multiplying those ten numbers together and adding the numbers and the result to a dictionary. Then I am increasing the index list values by 1, and repeating the process until I have run through the whole number.
Then I am trying to find the largest value in the dictionary, and have the program tell me that value.
The problem I am having is that I have an error checking mechanism in the program, which tells me how many key/value pairs I have in the dictionary. It should be 990, but instead I have 53.
If anyone can identify what the problem is, I will be eternally grateful.
Code to follow:
from functools import reduce
#define the number to test
testno = 7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
#declare initial variables
index=[]
products = {}
count = 0
#define functions
def product(x):
return reduce((lambda a,b: a*b),x)
def increm(y):
return [x+1 for x in y]
#def runproduct(x):
# return product
def testnos(x):
return [int(str(x)[y]) for y in index]
#define the initial index
for x in range(10):
index = index+[x]
runtime = len(str(testno))-10
#start the while loop
while count < runtime:
products[str(testnos(testno))] = product(testnos(testno))
index = increm(index)
count+=1
print("[+] Number of results: "+str(len(str(products.values))))
print("[+] The numbers with the largest product are: "+str(max(products.keys(),key=(lambda k:products[k]))))
You have a problem in your first print statement. You are currently converting your products into a string, which returns to you something like this
{'[0, 8, 1, 3, 5, 3, 3, 6, 2, 7]': 0, ..., '[7, 8, 4, 6, 8, 6, 2, 2, 4, 8]': 8257536}
Applying the len built-in over it will return the result 53. What you really want here is calling len directly over you products variable.
>>> print("[+] Number of results: {}".format(len(products)))
[+] Number of results: 990
Consider using the format function when building your string. You can use PyFormat website as reference.

Categories

Resources