How to generate all possible binary strings from a clue effectively? - python-3.x

I can get a clue in the form of a list (e.g. [1,3,1]) and the length of the string (e.g. 8) and I generate all possible strings given the clue. That is:
01011101
10111010
10111001
10011101
Having three groups of 1s separated by one or more 0s of length given by the clue (in that order).
The clue specifies lengths of groups of 1s separated by at least one 0. The order of these groups must follow the order in the clue list.
My approach would be to use recursion, where each call tries to insert a specific group of 1s in the string (in the order of the clue list). It uses a for-loop to place it in all possible indices of the string and recursively calls itself for each of these placements with a clue = clue[1:] and size = size - clue[0].
How can I do that effectively in Python?

I would just use combinations_with_replacement to generate all possible combinations and build your answers that way.
from itertools import combinations_with_replacement
from collections import Counter
def generate_answers(clue, length):
segs = len(clue) + 1 # segment indices that a zero can be placed
excess_zeros = length - sum(clue) - (segs - 2) # number of zeros that can be moved around
for comb in combinations_with_replacement(range(segs), excess_zeros):
count = Counter(comb) # number of zeros to be added to each segment
for i in range(1, len(clue)):
count[i] += 1 # add the zeros required to separate the ones
output = ''
for i in range(segs): # build string
output += '0' * count[i]
if i < len(clue):
output += '1' * clue[i]
print(output)
clue = [1, 3, 1]
length = 8
generate_answers(clue, length)
Output:
'01011101'
'10011101'
'10111001'
'10111010'

This is another way to do it (recursively) without external libraries:
def generate_answers(clue, size):
if len(clue) == 0:
return [[0 for _ in range(size)]]
groups = gen_groups(clue)
min_len = sum(clue) + len(clue) - 1
free_spaces = size - min_len
result = recursive_combinations(len(groups) + 1, free_spaces)
solution = []
for res in result:
in_progress = []
for i in range(len(groups)):
in_progress += [0 for _ in range(res[i])]
in_progress += groups[i]
in_progress += [0 for _ in range(res[-1])]
solution.append(in_progress)
return solution
def gen_groups(clue):
result = []
for elem in clue:
in_progress = []
for i in range(elem):
in_progress.append(1)
in_progress.append(0)
result.append(in_progress)
if len(result) > 0:
result[-1].pop()
return result
def recursive_combinations(fields, zeroes):
if fields <= 0 or zeroes< 0:
return []
if fields == 1:
return [[zeroes]]
solution = []
for i in range(zeroes+ 1):
result = recursive_combinations(fields - 1, zeroes- i)
solution += [[i] + res for res in result]
return solution

Related

Problem in the function of my program code python

I tried to make a program to do the below things but apparently, the function doesn't work. I want my function to take two or more arguments and give me the average and median and the maximum number of those arguments.
example input:
calc([2, 20])
example output : (11.0, 11.0, 20)
def calc():
total = 0
calc = sorted(calc)
for x in range(len(calc)):
total += int(calc[x])
average = total / len(calc)
sorted(calc)
maximum = calc[len(calc) - 1]
if len(calc) % 2 != 0:
median = calc[(len(calc) // 2) + 1]
else:
median = (float(calc[(len(calc) // 2) - 1]) + float(calc[(len(calc) // 2)])) / 2
return (average, median, maximum)
There are some things I'm going to fix as I go since I can't help myself.
First, you main problem is arguments.
If you hand a function arguments
calc([2, 20])
It needs to accept arguments.
def calc(some_argument):
This will fix your main problem but another thing is you shouldn't have identical names for your variables.
calc is your function name so it should not also be the name of your list within your function.
# changed the arg name to lst
def calc(lst):
lst = sorted(lst)
# I'm going to just set these as variables since
# you're doing the calculations more than once
# it adds a lot of noise to your lines
size = len(lst)
mid = size // 2
total = 0
# in python we can just iterate over a list directly
# without indexing into it
# and python will unpack the variable into x
for x in lst:
total += int(x)
average = total / size
# we can get the last element in a list like so
maximum = lst[-1]
if size % 2 != 0:
# this was a logical error
# the actual element you want is mid
# since indexes start at 0
median = lst[mid]
else:
# here there is no reason to explicity cast to float
# since python division does that automatically
median = (lst[mid - 1] + lst[mid]) / 2
return (average, median, maximum)
print(calc([11.0, 11.0, 20]))
Output:
(14.0, 11.0, 20)
Because you are passing arguments into a function that doesn't accept any, you are getting an error. You could fix this just by making the first line of your program:
def calc(calc):
But it would be better to accept inputs into your function as something like "mylist". To do so you would just have to change your function like so:
def calc(mylist):
calc=sorted(mylist)

Is the Benchmarking of my Algorithms right?

i wrote Quicksort and Mergesort and a Benchmark for them, to see how fast they are.
Here is my code:
#------------------------------Creating a Random List-----------------------------#
def create_random_list (length):
import random
random_list = list(range(0,length))
random.shuffle(random_list)
return random_list
# Initialize default list length to 0
random_list = create_random_list(0)
# Testing random list function
print ("\n" + "That is a randomized list: " + "\n")
print (random_list)
print ("\n")
#-------------------------------------Quicksort-----------------------------------#
"""
Recursive Divide and Conquer Algorithm
+ Very efficient for large data set
- Performance Depends largely on Pivot Selection
Time Complexity
--> Worst-Case -----> O (n^2)
--> Best-Case -----> Ω (n log (n))
--> Average Case ---> O (n log (n))
Space Complexity
--> O(log(n))
"""
# Writing the Quick Sort Algorithm for sorting the list - Recursive Method
def qsort (random_list):
less = []
equal = []
greater = []
if len(random_list)>1:
# Initialize starting Point
pivot = random_list[0]
for x in random_list:
if x < pivot:
less.append(x)
elif x == pivot:
equal.append(x)
elif x > pivot:
greater.append(x)
return qsort(less) + equal + qsort(greater)
else:
return random_list
"""
Build in Python Quick Sort:
def qsort(L):
if len(L) <= 1: return L
return qsort([lt for lt in L[1:] if lt < L[0]]) + L[0:1] + \
qsort([ge for ge in L[1:] if ge >= L[0]])
"""
# Calling Quicksort
sorted_list_qsort = qsort(random_list)
# Testint Quicksort
print ("That is a sorted list with Quicksort: " + "\n")
print (sorted_list_qsort)
print ("\n")
#-------------------------------------FINISHED-------------------------------------#
#-------------------------------------Mergesort------------------------------------#
"""
Recursive Divide and Conquer Algorithm
+
-
Time Complexity
--> Worst-Case -----> O (n l(n))
--> Best-Case -----> Ω (n l(n))
--> Average Case ---> O (n l(n))
Space Complexity
--> O (n)
"""
# Create a merge algorithm
def merge(a,b): # Let a and b be two arrays
c = [] # Final sorted output array
a_idx, b_idx = 0,0 # Index or start from a and b array
while a_idx < len(a) and b_idx < len(b):
if a[a_idx] < b[b_idx]:
c.append(a[a_idx])
a_idx+=1
else:
c.append(b[b_idx])
b_idx+=1
if a_idx == len(a): c.extend(b[b_idx:])
else: c.extend(a[a_idx:])
return c
# Create final Mergesort algorithm
def merge_sort(a):
# A list of zero or one elements is sorted by definition
if len(a)<=1:
return a
# Split the list in half and call Mergesort recursively on each half
left, right = merge_sort(a[:int(len(a)/2)]), merge_sort(a[int(len(a)/2):])
# Merge the now-sorted sublists with the merge function which sorts two lists
return merge(left,right)
# Calling Mergesort
sorted_list_mgsort = merge_sort(random_list)
# Testing Mergesort
print ("That is a sorted list with Mergesort: " + "\n")
print (sorted_list_mgsort)
print ("\n")
#-------------------------------------FINISHED-------------------------------------#
#------------------------------Algorithm Benchmarking------------------------------#
# Creating an array for iterations
n = [100,1000,10000,100000]
# Creating a dictionary for times of algorithms
times = {"Quicksort":[], "Mergesort": []}
# Import time for analyzing the running time of the algorithms
from time import time
# Create a for loop which loop through the arrays of length n and analyse their times
for size in range(len(n)):
random_list = create_random_list(n[size])
t0 = time()
qsort(random_list)
t1 = time()
times["Quicksort"].append(t1-t0)
random_list = create_random_list(n[size-1])
t0 = time()
merge_sort(random_list)
t1 = time()
times["Mergesort"].append(t1-t0)
# Create a table while shows the Benchmarking of the algorithms
print ("n\tMerge\tQuick")
print ("_"*25)
for i,j in enumerate(n):
print ("{}\t{:.5f}\t{:.5f}\t".format(j, times["Mergesort"][i], times["Quicksort"][i]))
#----------------------------------End of Benchmarking---------------------------------#
The code is well documented and runs perfectly with Python 3.8. You may copy it in a code editor for better readability.
--> My Question as the title states:
Is my Benchmarking right? I'm doubting it a litte bit, because the running times of my Algorithms seem a little odd. Can someone confirm my runtime?
--> Here is the output of this code:
That is a randomized list:
[]
That is a sorted list with Quicksort:
[]
That is a sorted list with Mergesort:
[]
n Merge Quick
_________________________
100 0.98026 0.00021
1000 0.00042 0.00262
10000 0.00555 0.03164
100000 0.07919 0.44718
--> If someone has another/better code snippet on how to print the table - feel free to share it with me.
The error is in n[size-1]: when size is 0 (the first iteration), this translates to n[-1], which corresponds to your largest size. So in the first iteration you are comparing qsort(100) with merge_sort(100000), which obviously will favour the first a lot. It doesn't help that you call this variable size, as it really isn't the size, but the index in the n list, which contains the sizes.
So remove the -1, or even better: iterate directly over n. And I would also make sure both sorting algorithms get to sort the same list:
for size in n:
random_list1 = create_random_list(size)
random_list2 = random_list1[:]
t0 = time()
qsort(random_list1)
t1 = time()
times["Quicksort"].append(t1-t0)
t0 = time()
merge_sort(random_list2)
t1 = time()
times["Mergesort"].append(t1-t0)
Finally, consider using timeit which is designed for measuring performance.

Dynamic Array Runtime Error - code working but not for large input values | How to resolve?

This is the code I wrote and seems like it's working but when I checked on the Hackerrank for testing with the huge test cases - it's giving me a runtime error.
How can I optimize this code?
def dynamicArray(n, queries):
lastAnswer = 0
seq = []
result = []
for k in range(0, n):
seq.append([])
for i in queries:
N_querytype = i[0] #it can be either 1 or 2
x = i[1]
y = i[2]
index = (x ^ lastAnswer) % n
if(N_querytype == 1):
seq[index].append(y)
elif(N_querytype == 2):
lastAnswer = seq[index][y]
result.append(lastAnswer)
return result
This is the test-case for which it is not running. Is there something I am missing?
Your answer was close but you misunderstood what to do in query 2
Find the value of element y % size in seq (where size is the size of seq) and assign it to
So using index you get the sequence which will be a list, but you are then asked to find the value in the list whic his indexed at position y % size where size = len(seq[index])
def dynamicArray(n, queries):
lastAnswer = 0
seq = []
result = []
for k in range(0, n):
seq.append([])
for i in queries:
N_querytype = i[0] #it can be either 1 or 2
x = i[1]
y = i[2]
index = (x ^ lastAnswer) % n
print("#", index, y)
if(N_querytype == 1):
seq[index].append(y)
elif(N_querytype == 2):
size = len(seq[index]) #Calculate the size of the sequnce at this index
lastAnswer = seq[index][y % size] #look up the value in this sequence at index y % size
result.append(lastAnswer)
return result

Can't figure out why my program is not creating a list

I need to compare each number in a list back to back, subtract, and add the outcome to a new list.
so
list1[1]-[0] = list2 [0]
list1[2]-[1] = list2 [1]
etc.
But I can't get it to do this.
Here is my block
change = []
index = 0
popyear_up = 1
popyear_low = 0
while index < len(data_numbers):
#for i in range, len(data_numbers:
difference = data_numbers[popyear_up] - data_numbers[popyear_low]
change.append(difference)
popyear_up += 1
popyear_low += 1
index += 1
The uncommented "while" line right now returns
difference = data_numbers[popyear_up] - data_numbers[popyear_low]
IndexError: list index out of range
The commented line only does [1]-[0] and [2]-[1], but does them correctly and appends them to change[]
I have no idea why it only does those 2. But for the first one I feel it has something to do with the length of my main list of data and the length of the list I'm asking it to create.
So two different issues, and I can't for the life of me figure out what I'm missing.
Full code if necessary
file = input('File to open: ')
infile = open(file, 'r')
source_file = infile.readlines()
infile.close()
index = 0
while index < len(source_file):
source_file[index] = source_file[index].rstrip('\n')
index += 1
data_numbers = [int(i) for i in source_file]
change = []
index = 0
popyear_up = 1
popyear_low = 0
while index < len(data_numbers):
#for i in range, len(data_numbers:
difference = data_numbers[popyear_up] - data_numbers[popyear_low]
change.append(difference)
popyear_up += 1
popyear_low += 1
index += 1
#start_year = 1950
#change_sum = float(sum(change))
#change_average = change_sum / len(change)
#max_change = start_year + change.index(max(n)) + 1
#min _change = start_year + change.index(min(n)) + 1
#print('Average Change in Population:',change_average)
#print ('Year with most population increas:',max_change)
#print ('Year with lease population increas:',min_change)
Since your lists are of the same length and one of the indices (popyear_up) is one ahead, it will break. Instead, only go up to index < len(data_numbers) - 1.
Also, just do this:
change = []
popyear_up = 1
popyear_low = 0
for popyear_low in range(len(data_numbers) - 1):
difference = data_numbers[popyear_low + 1] - data_numbers[popyear_low]
change.append(difference)
Also, just do this:
change = [data_numbers[i + 1] - data_numbers[i] for i in range(len(data_numbers) - 1)]
Or if you want (though this is slightly less readable):
change = [y - x for x, y in zip(data_numbers, data_numbers[1:])]

more elegant way to build and append lists?

I know this is a lame question but python newbie here. I came up with below and it works but I was wondering if there are more efficient ways to do this:
the goal here is calculate 4/1 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 .... n times
n = 5000
x = 1.0
list_1 = [] #make a list for denominator
list_2 = [] #make a list of fractions using list_1 as denominator
list_3 = [] #make a list change odd elements to negative
for i in range(n):
list_1.append(float(x))
x = x + 2
for i in range(len(list_1)):
list_2.append(4/list_1[i])
for count, i in enumerate(list_2):
if count % 2 == 0:
list_3.append(i)
else:
list_3.append(i * -1)
sum(list_3)
this would be a one-liner for your task:
s = sum((-1)**i * 4 / (2*i+1) for i in range(n))
it would be more efficient because no list is created (.append is never called); it just sums over a generator of all your elements.
if you really need the list of your elements (and not just the sum) you could construct it in a similar way:
lst = list((-1)**i * 4 / (2*i+1) for i in range(n))
you can try to do something like this, using a function:
def calc4DivX(n):
signal = 1
list_values = []
for k in range(n):
if signal == 1:
list_values.append(4/n)
else:
list_values.append(-4/n)
signal = signal*-1 # signal keeps alternating for every iteraction
return sum(list_values)
#Call the function
print(calc4DivX(value))

Resources