generate a list of increasing elements - python

I am trying to write a section of a larger program which will generate a list of random integers. the first randomly generated list should have X elements, and then generate another list of random integers with X + Y elements, and so on, sequentially adding Y to the number of elements until I get to a specified point. Each generated list will also be sorted using the selection sort method. I am using several different sort methods (selection, bubble, merge, quick, radix...) to calculate the execution time of each method for increasing input sizes. As far as the selection sort portion, I have this so far but the output I'm getting is 100 lists of 100 numbers. Clearly I'm still pretty new to Python.
Hoping for a breakthrough, thanks!
import time
import random
start_timeSelection = time.clock()
lst = []
count = 100
def selectionSort(lst):
count = 100
lst = [int(999*random.random()) for i in range(count)]
for i in range(len(lst) - 1):
currentMin = lst[i]
currentMinIndex = i
for j in range(i + 1, len(lst)):
if currentMin > lst[j]:
currentMin, currentMinIndex = lst[j], j
if currentMinIndex != i:
lst[currentMinIndex], lst[i] = lst[i], currentMin
print(lst)
while count < 300:
count += 100
selectionSort(lst)
s = (time.clock() - start_timeSelection)
print("Selection Sort execution time is: ", s, "seconds")

here is what you are looking for.
This code creates a list containing a random number of elements ranging from 0-9 (but you can change the range). Also it creates 10 lists(this number can also be changed). Each new list is a random length + the previous list's length:
from random import randint
X_plus_Y = 0
x = 0
while x < 10: #change 10 to make desired number of lists
lst = []
num_of_elements = randint(0,9) #change 9 for different random range
X_plus_Y += num_of_elements
print("add "+str(num_of_elements)+" equals " + str(X_plus_Y))
for i in range(X_plus_Y):
lst.append(randint(0,9))
print(lst)
print("\n")
x += 1
hope this helped

Here's a short example that uses a generator and list comprehension to generate lists of random values with increasing length.
import random
def generate_list(start_len, incr_len):
i = 0
while True:
yield [random.random() for j in range(start_len + i * incr_len)]
i += 1
gl = generate_list(start_len=2, incr_len=3)
print(next(gl)) # [0.3401864808412862, 0.33105346208017106]
print(next(gl)) # [0.5075146706165449, 0.5802519757892776, 0.5244104797659368, 0.8235816542342208, 0.3669745504311662]

Related

Python - Pull random numbers from a list. Populate a new list with a specified length and sum

I am trying to create a function where:
The output list is generated from random numbers from the input list
The output list is a specified length and adds to a specified sum
ex. I specify that I want a list that is 4 in length and adds up to 10. random numbers are pulled from the input list until the criteria is satisfied.
I feel like I am approaching this problem all wrong trying to use recursion. Any help will be greatly appreciated!!!
EDIT: for more context on this problem.... Its going to be a random enemy generator.
The end goal input list will be coming from a column in a CSV called XP. (I plan to use pandas module). But this CSV will have a list of enemy names in the one column, XP in another, Health in another, etc. So the end goal is to be able to specify the total number of enemies and what the sum XP should be between those enemies and have the list generate with the appropriate information. For ex. 5 enemies with a total of 200 XP between them. The result is maybe -> Apprentice Wizard(50 xp), Apprentice Wizard(50 xp), Grung(50), Xvart(25 xp), Xvart(25 xp). The output list will actually need to include all of the row information for the selected items. And it is totally fine to have duplicated in the output as seen in this example. That will actually make more sense in the narrative of the game that this is for.
The csv --> https://docs.google.com/spreadsheets/d/1PjnN00bikJfY7mO3xt4nV5Ua1yOIsh8DycGqed6hWD8/edit?usp=sharing
import random
from random import *
lis = [1,2,3,4,5,6,7,8,9,10]
output = []
def query (total, numReturns, myList, counter):
random_index = randrange(len(myList)-1)
i = myList[random_index]
h = myList[i]
# if the problem hasn't been solved yet...
if len(output) != numReturns and sum(output) != total:
print(output)
# if the length of the list is 0 (if we just started), then go ahead and add h to the output
if len(output) == 0 and sum(output) + h != total:
output.append(h)
query (total, numReturns, myList, counter)
#if the length of the output is greater than 0
if len(output) > 0:
# if the length plus 1 is less than or equal to the number numReturns
if len(output) +1 <= numReturns:
print(output)
#if the sum of list plus h is greater than the total..then h is too big. We need to try another number
if sum(output) + h > total:
# start counter
for i in myList:# try all numbers in myList...
print(output)
print ("counter is ", counter, " and i is", i)
counter += 1
print(counter)
if sum(output) + i == total:
output.append(i)
counter = 0
break
if sum(output) + i != total:
pass
if counter == len(myList):
del(output[-1]) #delete last item in list
print(output)
counter = 0 # reset the counter
else:
pass
#if the sum of list plus h is less than the total
if sum(output) + h < total:
output.append(h) # add h to the list
print(output)
query (total, numReturns, myList, counter)
if len(output) == numReturns and sum(output) == total:
print(output, 'It worked')
else:
print ("it did not work")
query(10, 4, lis, 0)
I guess that it would be better to get first all n-size combinations of given array which adds to specified number, and then randomly select one of them. Random selecting and checking if sum is equal to specified value, in pessimistic scenario, can last indefinitely.
from itertools import combinations as comb
from random import randint
x = [1,1,2,4,3,1,5,2,6]
def query(arr, total, size):
combs = [c for c in list(comb(arr, size)) if sum(c)==total]
return combs[randint(0, len(combs))]
#example 4-item array with items from x, which adds to 10
print(query(x, 10, 4))
If the numbers in your input list are consecutive numbers, then this is equivalent to the problem of choosing a uniform random output list of N integers in the range [min, max], where the output list is ordered randomly and min and max are the smallest and largest number in the input list. The Python code below shows how this can be solved. It has the following advantages:
It does not use rejection sampling.
It chooses uniformly at random from among all combinations that meet the requirements.
It's based on an algorithm by John McClane, which he posted as an answer to another question. I describe the algorithm in another answer.
import random # Or secrets
def _getSolTable(n, mn, mx, sum):
t = [[0 for i in range(sum + 1)] for j in range(n + 1)]
t[0][0] = 1
for i in range(1, n + 1):
for j in range(0, sum + 1):
jm = max(j - (mx - mn), 0)
v = 0
for k in range(jm, j + 1):
v += t[i - 1][k]
t[i][j] = v
return t
def intsInRangeWithSum(numSamples, numPerSample, mn, mx, sum):
""" Generates one or more combinations of
'numPerSample' numbers each, where each
combination's numbers sum to 'sum' and are listed
in any order, and each
number is in the interval '[mn, mx]'.
The combinations are chosen uniformly at random.
'mn', 'mx', and
'sum' may not be negative. Returns an empty
list if 'numSamples' is zero.
The algorithm is thanks to a _Stack Overflow_
answer (`questions/61393463`) by John McClane.
Raises an error if there is no solution for the given
parameters. """
adjsum = sum - numPerSample * mn
# Min, max, sum negative
if mn < 0 or mx < 0 or sum < 0:
raise ValueError
# No solution
if numPerSample * mx < sum:
raise ValueError
if numPerSample * mn > sum:
raise ValueError
if numSamples == 0:
return []
# One solution
if numPerSample * mx == sum:
return [[mx for i in range(numPerSample)] for i in range(numSamples)]
if numPerSample * mn == sum:
return [[mn for i in range(numPerSample)] for i in range(numSamples)]
samples = [None for i in range(numSamples)]
table = _getSolTable(numPerSample, mn, mx, adjsum)
for sample in range(numSamples):
s = adjsum
ret = [0 for i in range(numPerSample)]
for ib in range(numPerSample):
i = numPerSample - 1 - ib
# Or secrets.randbelow(table[i + 1][s])
v = random.randint(0, table[i + 1][s] - 1)
r = mn
v -= table[i][s]
while v >= 0:
s -= 1
r += 1
v -= table[i][s]
ret[i] = r
samples[sample] = ret
return samples
Example:
weights=intsInRangeWithSum(
# One sample
1,
# Count of numbers per sample
4,
# Range of the random numbers
1, 5,
# Sum of the numbers
10)
# Divide by 100 to get weights that sum to 1
weights=[x/20.0 for x in weights[0]]

Index out of range error when creating a random list with no consecutive repetitions

I am trying to generate a list of 100 elements which consist of the numbers 1 to 4 randomly distributed, but without consecutive repetitions. I do not want to determine whether the numbers 1 to 4 occur the same number of times, I want it to be completely random except for having no consecutive repetitions. I wrote some code that seems to be doing that until it stops and says
list index out of range, however I cannot figure out why this error is happening.
from random import randint
guesses = []
for x in range (0, 99):
guess = randint(1,4)
guesses.append(guess)
if x> 0 and guesses[x] == guesses[x-1]:
guesses.remove(guess)
print(guesses)
It should look something like this:
123421342312321423124213...23142314213
Your problem is that the number keeps increasing even when you remove a number instead of decreasing. I would recommend using a while loop instead. Also, you should only add the number to your list if needed instead of adding it then removing it.
from random import randint
guesses = [randint(1,4)]
x = 1
while x < 100:
guess = randint(1,4)
if guess != guesses[x-1]:
guesses.append(guess)
x += 1
print(guesses)
here is a solution using numpy
from time import time
import numpy as np
def solve_random_non_consecutive(minValue,maxValue,size):
# initial guess
a = np.random.randint(minValue,maxValue,size)
# indexes where a[i] == a[i-1]
x = np.where(np.diff(a) == 0)[0]
# as long as we have consecutive duplicates
while len(x) > 0:
# rerandomize all indexes
a[x] = np.random.randint(minValue,maxValue,len(x))
# find all duplicates
x = np.where(np.diff(a) == 0)[0]
return a
s = time()
print(solve_random_non_consecutive(1,5,1000000))
print("Took %0.2fs to solve"%(time()-s)) # took ~ 0.17 seconds to generate 1MIL
# any of the solutions using iteration took ~ 10 seconds to generate 1 mil
some caveats are that since its repopulating the data randomly the amount of time may vary from run to run
Your code would work if instead of removing the element that matches the one before, you replace it until it doesn't:
from random import randint
guesses = [randint(1,4)]
for x in range (1, 100):
guess = randint(1,4)
guesses.append(guess)
while guesses[x] == guesses[x-1]:
guesses[x] = randint(1,4)
Two alternate ideas:
You could create a set of your choices:
{1, 2, 3, 4}
And then on each iteration ask for a random.choice from the set - the last item. choice needs something indexible so you need to convert to a list each time, but there might be some ways to make that more efficient if this is a bottleneck:
from random import choice
choices = {1, 2, 3, 4}
l = [choice(list(choices))] # start with one random choice
for i in range(99):
l.append(choice(list(choices - {l[-1]})))
This seems to be pretty uniform:
from collections import Counter
counts = Counter(l)
counts
Counter({3: 26, 2: 25, 1: 26, 4: 23})
Use Iterators
You can do this all with iterators that evaluate lazily, then just take an islice() of the length you want:
from random import randint
from itertools import tee, islice
#generator to makes random ints between start and stop
def randIt(start, stop):
while True:
yield randint(1,4)
rands, prevs = tee(randIt(1, 4))
next(prevs)
# non_dupes is a generator that makes non-repeating rands
non_dupes = (r for r, i in zip(rands, prevs) if r!=i)
# use itertools islice or a loop to get the number you want
# or just call `next(non_dupes)` for one:
list(islice(non_dupes, 0, 100))
I had a similar problem this week, my solution was that I had to adjust my counter(x it looks like for you) every time I removed an index because the array gets shorter so things start to shift around.
The problem is once you remove an element, x becomes larger than the size of your array
so guesses[x] is out of bounds because x >= guesses.size()
You're only generating 99 elements. Range(0,99) goes from 0 to 98 including 0 to total 99 elements.
Also, the part of your code which removes duplicate guesses needs to set x back to x - 1. This way the "counter" for each element you want to create is not 1 ahead of how many elements you actually have.
Additionally, when you remove this element, that method will remove the first instance of a object equal to the variable guess, not necessarily the one you just added. You should use .pop() View the example in python I screenshotted.
for x in range (0, 100):
guess = randint(1,4)
guesses.append(guess)
if x> 0 and guesses[x] == guesses[x-1]:
guesses.pop()
x = x - 1
When you remove an element from the guesses array, its length will decrement
use this code
from random import randint
guesses = []
x = 0
while x < 100:
guess = randint(1,4)
guesses.append(guess)
if x > 0 and guesses[x] == guesses[x-1]:
guesses.pop()
else:
x += 1
print(guesses)

Multiplying every Nth element in a list by M

I have a problem I can't seem to figure out. I am very new to Python and have only been coding for three weeks. Any help is appreciated.
Problem:
We are passing in 3 inputs:
a list of numbers
a multiplier value, M
a value, N
You should multiply every Nth element (do not multiply the 0th element) by M. So if N is 3, you start with the 3rd element, which is index 2.
If there are less than N elements then you should output the unchanged input list.
I can't seem to figure this out. I have tried many different things here. Currently, I have the following, which is not working at all.
Provided:
import sys
M= int(sys.argv[2])
N= int(sys.argv[3])
numbers= sys.argv[1].split(',')
for i in range(0, len(numbers)):
numbers[i]= int(numbers[i])
My Code:
for N in numbers:
if numbers[i] > 0:
total = N * M
print(total)
else:
print(numbers)
Output:
I am not even close to what the output should be. Feeling lost on this. Here is what my code comes to. It looks like they want the output in a list.
Program Failed for Input: 1,2,3,4,5,6 5 3
Expected Output: [1, 2, 15, 4, 5, 30]
Your Program Output:
5
10
15
20
25
30
You could try a list comprehension with slicing.
numbers[N-1::N] = [x * M for x in numbers[N-1::N]]
A more elegant solution using list comprehensions ;)
[item*M if (index and not (index+1)%N) else item for index, item in enumerate(items)]
This solution is based on your original one. A more pythonic one would use for instance, a list comprehension so keep that in mind in the future,
output = [numbers[0]]
if len(numbers) >= N:
for i in range(1,len(numbers)):
if ((i+1)%N) is 0:
output.append(numbers[i]*M)
else:
output.append(numbers[i]);
else:
output = numbers
If N is not larger than the list size, the program constructs a new list of numbers with each Nth number being multiplied by M. This is done with a simple modulo operator. Indexing in Python starts with zero and i iterates through index values but your desired output counts the elements as if starting from 1 - thus i+1 in the modulo. If it is not every Nth - program just append the old value. If the list is shorter than N altogether, it assigns the whole unchanged list to the output list.
will this work for you?
res = []
for num in numbers:
if num > 0:
total = num * M
res.append(total)
if len(res) != len(numbers):
print (numbers)
else:
res.reverse()
print (res)
So after many attempts and bouncing this off of a friend who works as a programmer, I ended up with this that gave me the proper output:
newlist = []
if len(numbers) < N:
newlist = numbers
else:
for i in range(0, len(numbers)):
num = numbers[i]
if (i+1) % N == 0:
newlist.append(num*M)
else:
newlist.append(num)
i+=1
print(newlist)
# Input
import sys
M= int(sys.argv[2])
N= int(sys.argv[3])
# convert strings to integers
numbers= sys.argv[1].split(',')
for i in range(0, len(numbers)):
numbers[i]= int(numbers[i])
# if the length of our list is greater than our supplied value
# loop to multiply(starting at the 3rd position in the list) by M
if len(numbers) > N :
for num in range(2, len(numbers), 3) :
numbers[num] = numbers[num] * M
print(numbers)

Subset sum algorithm a little faster than 2^(n/2) in worst time?

After analyzing the fastest subset sum algorithm which runs in 2^(n/2) time, I noticed a slight optimization that can be done. I'm not sure if it really counts as an optimization and if it does, I'm wondering if it can be improved by recursion.
Basically from the original algorithm: http://en.wikipedia.org/wiki/Subset_sum_problem (see part with title Exponential time algorithm)
it takes the list and splits it into two
then it generates the sorted power sets of both in 2^(n/2) time
then it does a linear search in both lists to see if 1 value in both lists sum to x using a clever trick
In my version with the optimization
it takes the list and removes the last element last
then it splits the list in two
then it generates the sorted power sets of both in 2^((n-1)/2) time
then it does a linear search in both lists to see if 1 value in both lists sum to x or x-last (at same time with same running time) using a clever trick
If it finds either, then I will know it worked. I tried using python time functions to test with lists of size 22, and my version is coming like twice as fast apparently.
After running the below code, it shows
0.050999879837 <- the original algorithm
0.0250000953674 <- my algorithm
My logic for the recursion part is, well if it works for a size n list in 2^((n-1)/1) time, can we not repeat this again and again?
Does any of this make sense, or am I totally wrong?
Thanks
I created this python code:
from math import log, ceil, floor
import helper # my own code
from random import randint, uniform
import time
# gets a list of unique random floats
# s = how many random numbers
# l = smallest float can be
# h = biggest float can be
def getRandomList(s, l, h):
lst = []
while len(lst) != s:
r = uniform(l,h)
if not r in lst:
lst.append(r)
return lst
# This just generates the two powerset sorted lists that the 2^(n/2) algorithm makes.
# This is just a lazy way of doing it, this running time is way worse, but since
# this can be done in 2^(n/2) time, I just pretend its that running time lol
def getSortedPowerSets(lst):
n = len(lst)
l1 = lst[:n/2]
l2 = lst[n/2:]
xs = range(2**(n/2))
ys1 = helper.getNums(l1, xs)
ys2 = helper.getNums(l2, xs)
return ys1, ys2
# this just checks using the regular 2^(n/2) algorithm to see if two values
# sum to the specified value
def checkListRegular(lst, x):
lst1, lst2 = getSortedPowerSets(lst)
left = 0
right = len(lst2)-1
while left < len(lst1) and right >= 0:
sum = lst1[left] + lst2[right]
if sum < x:
left += 1
elif sum > x:
right -= 1
else:
return True
return False
# this is my improved version of the above version
def checkListSmaller(lst, x):
last = lst.pop()
x1, x2 = x, x - last
return checkhelper(lst, x1, x2)
# this is the same as the function 'checkListRegular', but it checks 2 values
# at the same time
def checkhelper(lst, x1, x2):
lst1, lst2 = getSortedPowerSets(lst)
left = [0,0]
right = [len(lst2)-1, len(lst2)-1]
while 1:
check = 0
if left[0] < len(lst1) and right[0] >= 0:
check += 1
sum = lst1[left[0]] + lst2[right[0]]
if sum < x1:
left[0] += 1
elif sum > x1:
right[0] -= 1
else:
return True
if left[1] < len(lst1) and right[1] >= 0:
check += 1
sum = lst1[left[1]] + lst2[right[1]]
if sum < x2:
left[1] += 1
elif sum > x2:
right[1] -= 1
else:
return True
if check == 0:
return False
n = 22
lst = getRandomList(n, 1, 3000)
startTime = time.time()
print checkListRegular(lst, -50) # -50 so it does worst case scenario
startTime2 = time.time()
print checkListSmaller(lst, -50) # -50 so it does worst case scenario
startTime3 = time.time()
print (startTime2 - startTime)
print (startTime3 - startTime2)
This is the helper library which I just use to generate the powerset list.
def dec_to_bin(x):
return int(bin(x)[2:])
def getNums(lst, xs):
sums = []
n = len(lst)
for i in xs:
bin = str(dec_to_bin(i))
bin = (n-len(bin))*"0" + bin
chosen_items = getList(bin, lst)
sums.append(sum(chosen_items))
sums.sort()
return sums
def getList(binary, lst):
s = []
for i in range(len(binary)):
if binary[i]=="1":
s.append(float(lst[i]))
return s
then it generates the sorted power sets of both in 2^((n-1)/2) time
OK, since now the list has one less lement. However, this is not a big deal its just a constant time improvement of 2^(1/2)...
then it does a linear search in both lists to see if 1 value in both lists sum to x or x-last (at same time with same running time) using a clever trick
... and this improvement will go away because now you do twice as many operations to check for both x and x-last sums instead of only for x
can we not repeat this again and again?
No you can't, for the same reason why you couldn't split the original algorithm again and again. The trick only works for once because once you start looking for values in more than two lists you can't use the sorting trick anymore.

Interviewstreet's Insertion sort program

I tried to program Interiewstreet's Insertion sort challenge Link for the challenge
in Python and here is my code shown below.
The program runs fine for a limit(which I'm not sure of) of input elements, but returns a false output for inputs of larger sizes. Can anyone guide me what am I doing wrong?
# This program tries to identify number of times swapping is done to sort the input array
"""
=>Get input values and print them
=>Get number of test cases and get inputs for those test cases
=>Complete Insertion sort routine
=>Add a variable to count the swapping's
"""
def sort_swap_times(nums):
""" This function takes a list of elements and then returns the number of times
swapping was necessary to complete the sorting
"""
times_swapped = 0L
# perform the insertion sort routine
for j in range(1, len(nums)):
key = nums[j]
i = j - 1
while i >= 0 and nums[i] > key:
# perform swap and update the tracker
nums[i + 1] = nums[i]
times_swapped += 1
i = i - 1
# place the key value in the position identified
nums[i + 1] = key
return times_swapped
# get the upper limit.
limit = int(raw_input())
swap_count = []
# get the length and elements.
for i in range(limit):
length = int(raw_input())
elements_str = raw_input() # returns a list of strings
# convert the given elements from str to int
elements_int = map(int, elements_str.split())
# pass integer elements list to perform the sorting
# get the number of times swapping was needed and append the return value to swap_count list
swap_count.append(sort_swap_times(elements_int))
# print the swap counts for each input array
for x in swap_count:
print x
Your algorithm is correct, but this is a naive approach to the problem and will give you a Time Limit Exceed signal on large test cases (i.e., len(nums) > 10000). Let's analyze the run-time complexity of your algorithm.
for j in range(1, len(nums)):
key = nums[j]
i = j - 1
while i >= 0 and nums[i] > key:
# perform swap and update the tracker
nums[i + 1] = nums[i]
times_swapped += 1
i = i - 1
# place the key value in the position identified
nums[i + 1] = key
The number of steps required in the above snippet is proportional to 1 + 2 + .. + len(nums)-1, or len(nums)*(len(nums)-1)/2 steps, which is O(len(nums)^2).
Hint:
Use the fact that all values will be within [1,10^6]. What you are really doing here is finding the number of inversions in the list, i.e. find all pairs of i < j s.t. nums[i] > nums[j]. Think of a data structure that allows you to find the number of swaps needed for each insert operation in logarithmic time complexity. Of course, there are other approaches.
Spoiler:
Binary Indexed Trees

Categories