Is there a efficient way to iterate through? - python

I am using python for prototyping the following expression :
(n1^i1)*(n2^i2)*......*(n10^i10) = output/input_min (where I have to store i1,i2,i3,..)
I wrote something like this for only 3 elements.
passes = []
max_pass = 8
for i in range(0,max_pass):
for j in range(0,max_pass):
for k in range(0,max_pass):
temp = np.array([i, j, k])
comp = np.round(np.prod(basis**temp), 3)
ratio = np.round(self.output/self.input_min, 3)
if comp == ratio:
passes.append([i, j, k])
Considering I know n1,n2,...,n10 and the rigth hand ratio, Is there a way I can do it without writing 10 nested loops? (i1,i2,...i10 has to be integers)

Use an array of counters, all initialized to zero.
Form an endless loop where you increment the first counter. When the counter reaches the maximum value, reset it to zero and carry to the next counter. The next counter follows the same logics, and so on.
So the outer loop will include an inner carry propagation loop.
Processing terminates when the last counter carries.

Related

Python bubble sort breaks with large numbers only

Im trying to create a bubble sort test algorithm that generates x amount of random integers and outputs to console and a text file. The number of numbers created as well as the max value for the random integers is determined by the variable bigsize. The code seems to work up to around when big size is ~2300, sometimes its more and sometimes it's less. I can always get 2000 to work though.
Edit: Also worth noting, it seems that the code breaks during the sorting process, as I get get a file to output unsorted numbers with no issues.
import random
import sys
bigsize = 2000
def main():
sys.setrecursionlimit(7000)
array = create_list()
print_array(array)
bubble_sort(array)
display_out(array)
def create_list():
array = [0] * bigsize
for x in range(bigsize):
array[x] = random.randint(0, bigsize)
return array
def bubble_sort(array):
increment = 0
buffer = 0
for x in range(len(array) - 1):
if (array[increment + 1] <= array[increment]):
buffer = array[increment + 1]
array[increment + 1] = array[increment]
array[increment] = buffer
increment = increment + 1
increment = 0
for x in range(len(array) - 1):
if (array[increment + 1] >= array[increment]):
increment = increment + 1
elif (array[increment + 1] < array[increment]):
bubble_sort(array)
def display_out(array):
for x in range(bigsize):
print(array[x])
main()
You have a dysfunctional sort. First and foremost, there is nothing useful about your recursion: you don't reduce the task -- you simply use recursion in place of the sort's outer loop. At that, you have implemented it incorrectly. I strongly recommend that you get more practice with the more basic skills of programming before you tackle recursion.
The first (non-)problem is a simple inefficiency: your loop has x as the index, but the loop body ignores x, while it maintains increment with the same value. There is no reason to have two separate variables. You can see how this is used in almost any bubble sort on the web:
for pos in range(len(array) - 1):
if array[pos+1] < array[pos]:
# switch the elements
You have a similar inefficiency in the second loop:
increment = 0
for x in range(len(array) - 1):
if (array[increment + 1] >= array[increment]):
increment = increment + 1
Again, you ignore x and maintain increment at the same value ... up until you find elements out of order:
elif (array[increment + 1] < array[increment]):
bubble_sort(array)
When you do so, you recur, but without altering increment. When you return from this recursion, the array must be properly sorted (assuming that the recursion logic is correct), and then you continue with this loop, iterating through the now-sorted array, ensuring up to bigsize times that the array is in order.
This entire loop is silly: if you simply set a flag when you make a switch in the first loop, you'll know whether or not you need to sort again. You'll do one extra iteration, but that doesn't affect the time complexity.
For instance:
done = True
for pos in range(len(array) - 1):
if array[pos+1] < array[pos]:
array[pos], array[pos+1] = array[pos+1], array[pos]
# Replace the second loop entirely
if not done:
bubble_sort(array)
I strongly recommend that you check the operation of your program by properly tracing the results. First, however, clean up the logic. Remove (for now) the superfluous code that writes to files, put in some basic tracing print statements, and study existing bubble sorts to see where you're making this all too "wordy". In fact, remove the recursion and simply repeat the sorting until done.
When I try this with bigsize=5000, it recurs to 3818 levels and quits. I'll leave the tracing up to you, if the problem is still there once you've cleaned up the program. There's not much point to fixing the "silent death" until you tighten the logic and trace the operation, so that you know you're fixing an otherwise working program. The current code does not "Make it easy for others to help you", as the posting guidelines say.

Program correctness for a cubic sort program

I would like some help in proving my loop invariant for my python cubic sort program.
So far I figured out the loop invariant which has two parts
0 <= i+1 <= len(L)
L[0:i+1] is sorted.
def cubicSort(L):
i = 0
while i + 1 < len(L):
if L[i] > L[i + 1]:
L[i], L[i + 1] = L[i + 1], L[i] # That is, swap L[i] and L[i + 1].
i = 0
else:
i = i + 1
the precondition is L is a list of integers
the post: is that the list is permuted and sorted
I don't know how to approach the proof
There are two elements to a proof of correctness: you must prove that when the algorithm terminates, the result is correct; and you must prove that the algorithm does terminate.
Your two loop invariants are both right, but you do need to prove that they are invariants. To show this, you must show that they are true before the first iteration of the loop, and if they are true before some iteration then they will be true after that iteration.
After that's done, it's straightforward that when the loop terminates, i + 1 == len(L) and hence L[0:i+1] equals L, so it follows that L is sorted when the loop terminates.
Usually it is more straightforward to show that the algorithm terminates, by finding a loop variant - an integer quantity which gets smaller on each iteration of the loop, and which causes the loop to terminate when the quantity reaches 0. But for this algorithm, there is no obvious variant because the loop counter i is reset to 0 within the loop, meaning this variable doesn't simply keep getting bigger or smaller monotonically.
The key for this proof is to consider the number of inversions in the list, where an "inversion" means a pair of list elements which are out of order. On each iteration, either i gets bigger, or i is reset to 0 but the number of inversions is decreased by 1. It's not possible for i to keep getting bigger and for the number of inversions to keep getting smaller without either i reaching the while loop bound, or the number of inversions reaching 0. Once there are no inversions left in the list, L[i] > L[i + 1] is always false, so i will continue to increase up to the bound and then the loop terminates, as required.

Make the code run faster without nested loop

I am trying to solve assignment problem, the code I wrote takes extremely long to run. I think it's due to nested loop I used. Is there another way to rewrite the code to make it more efficient.
The question I am trying to solve. Basically, starting at first element to compare with every element to its right. if it is larger than the rest, it will be "dominator". Then the second element to compare with every element to its right again. All the way to the last element which will be automatically become "dominator"
def count_dominators(items):
if len(items) ==0:
return len(items)
else:
k = 1
for i in range(1,len(items)):
for j in items[i:]:
if items[i-1]>j:
k = k+1
else:
k = k+0
return k
You can use a list comprehension to check if each item is a "dominator", then take the length - you have to exclude the final one to avoid taking max of an empty list, then we add 1 because we know that the final one is actually a dominator.
num_dominators = len([i for i in range(len(items) - 1) if items[i] > max(items[i + 1:])]) + 1
This is nice because it fits on one line, but the more efficient (single pass through the list) way to do it is to start at the end and every time we find a new number bigger than any we have seen before, count it:
biggest = items[-1]
n = 1
for x in reversed(items):
if x > biggest:
biggest = x
n+=1
return n

How to update array Index in loop (IndexError: list index out of range)

I should not use advance function, as this is a logical test during interview.
Trying to remove all digits which appear more than once in array.
testcase:
a=[1,1,2,3,2,4,5,6,7]
code:
def dup(a):
i=0
arraySize = len(a)
print(arraySize)
while i < arraySize:
#print("1 = ",arraySize)
k=i+1
for k in range(k,arraySize):
if a[i] == a[k]:
a.remove(a[k])
arraySize -= 1
#print("2 = ",arraySize)
i += 1
print(a)
result should be : 1,2,3,4,5,6,7
But i keep getting index out of range. i know that it is because the array list inside the loop changed, so the "while" initial index is different with the new index.
The question is : any way to sync the new index length (array inside the loop) with the parent loop (index in "while" loop) ?
The only thing i can think of is to use function inside the loop.
any hint?
Re-Calculating Array Size Per Iteration
It looks like we have a couple issues here. The first issue is that you can't update the "stop" value in your inner loop (the range function). So first off, let's remove that and use another while loop to give us the ability to re-calculate our array size every iteration.
Re-Checking Values Shifted Into Removed List Spot
Next, after you fix that you will run into a larger issue. When you use remove it moves a value from the end of the list or shifts the entire list to the left to use the removed spot, and you are not re-checking the value that got moved into the old values removed spot. To resolve this, we need to decrement i whenever we remove an element, this makes sure we are checking the value that gets placed into the removed elements spot.
remove vs del
You should use del over remove in this case. remove iterates over the list and removes the first occurrence of the value and it looks like we already know the exact index of the value we want to remove. remove might work, but it's usage here over complicates things a bit.
Functional Code with Minimal Changeset
def dup(a):
i = 0
arraySize = len(a)
print(arraySize)
while i < arraySize:
k = i + 1
while k < arraySize: # CHANGE: use a while loop to have greater control over the array size.
if a[i] == a[k]:
print("Duplicate found at indexes %d and %d." % (i, k))
del a[i] # CHANGE: used del instead of remove.
i -= 1 # CHANGE: you need to recheck the new value that got placed into the old removed spot.
arraySize -= 1
break
k += 1
i += 1
return a
Now, I'd like to note that we have some readability and maintainability issues with the code above. Iterating through an array and manipulating the iterator in the way we are doing is a bit messy and could be prone to simple mistakes. Below are a couple ways I'd implement this problem in a more readable and maintainable manner.
Simple Readable Alternative
def remove_duplicates(old_numbers):
""" Simple/naive implementation to remove duplicate numbers from a list of numbers. """
new_numbers = []
for old_number in old_numbers:
is_duplicate = False
for new_number in new_numbers:
if old_number == new_number:
is_duplicate = True
if is_duplicate == False:
new_numbers.append(old_number)
return new_numbers
Optimized Low Level Alternative
def remove_duplicates(numbers):
""" Removes all duplicates in the list of numbers in place. """
for i in range(len(numbers) - 1, -1, -1):
for k in range(i, -1, -1):
if i != k and numbers[i] == numbers[k]:
print("Duplicate found. Removing number at index: %d" % i)
del numbers[i]
break
return numbers
You could copy contents in another list and remove duplicates from that and return the list. For example:
duplicate = a.copy()
f = 0
for j in range(len(a)):
for i in range(len(duplicate)):
if i < len(duplicate):
if a[j] == duplicate[i]:
f = f+1
if f > 1:
f = 0
duplicate.remove(duplicate[i])
f=0
print(duplicate)

Python: How can I make my implementation of bubble sort more time efficient?

Here is my code - a bubble sort algorithm for sorting list elements in asc order:
foo = [7, 0, 3, 4, -1]
cnt = 0
for i in foo:
for i in range(len(foo)-1):
if foo[cnt] > foo[cnt + 1]:
temp = foo[cnt]
c[cnt] = c[cnt + 1]
c[cnt + 1] = temp
cnt = cnt + 1
cnt = 0
I've been revising my code, but it is still too inefficient for an online judge. Some help would be greatly appreciated!
Early Exit BubbleSort
The first loop has no bearing on what happens inside
The second loop does all the heavy lifting. You can get rid of count by using enumerate
To swap elements, use the pythonic swap - a, b = b, a.
As per this comment, make use of an early exit. If there are no swaps to be made at any point in the inner loop, that means the list is sorted, and no further iteration is necessary. This is the intuition behind changed.
By definition, after the ith iteration of the outer loop, the last i elements will have been sorted, so you can further reduce the constant factor associated with the algorithm.
foo = [7, 0, 3, 4, -1]
for i in range(len(foo)):
changed = False
for j, x in enumerate(foo[:-i-1]):
if x > foo[j + 1]:
foo[j], foo[j + 1] = foo[j + 1], foo[j]
changed = True
if not changed:
break
print(foo)
[-1, 0, 3, 4, 7]
Note that none of these optimisations change the asymptotic (Big-O) complexity of BubbleSort (which remains O(N ** 2)), instead, only reduces the constant factors associated.
One easy optimization is to start second loop from i+1 index:
for i in range(0, len(foo)):
for j in range(i+1, len(foo)):
if (foo[i] > foo[j]):
temp = foo[i]
foo[i] = foo[j]
foo[j] = temp
Since you already sorted everything up to index i there is no need to iterate over it again. This can save you more than 50% of comparisons - in this case it's 10 versus 25 in your original algorithm.
You need to understand the big Oh notation in order to understand how efficient your algorithm is in terms of usage of computational resources independent of computer architecture or clock rate. It basically helps you analyze the worst case running time or memory usage of your algorithm as the size of the input increases.
In summary, the running time of your algorithm will fall into one of these categories (from fastest to slowest);
O(1): Constant time. Pronounced (Oh of 1). The fastest time.
O(lg n): Logarithmic time. Pronounced (Oh of log n). Faster than linear time.
Traditionally, it is the fastest time bound for search.
O(n): Linear time. Pronounced (Oh of n, n is the size of your input e.g size of
an array). Usually something when you need to examine every single bit of
your input.
O(nlgn): The fastest time we can currently achieve when performing a sort on a
list of elements.
O(n**2): Oh of n squared. Quadratic time. Often this is the bound when we have
nested loops.
O(2**n): Really, REALLY big! A number raised to the power of n is slower than
n raised to any power.
In your case, you are using nested loops which is O(n2). The code i have written uses a single while loop and has a growth complexity of O(n) which is faster than O(n2). I haven't really tried it on a very large array but in your case it seems to work. Try it and let me know if it works as expected.
k = [7, 0, 3, 4, -1]
n = len(k)
i = 0
count = 0
while count < n**2: # assuming we wouldn't go through the loop more than n squared times
if i == n - 1:
i = 0
count += 1
swapped = False
elif k[i] > k[i+1]:
temp = k[i]
k[i] = k[i+1]
k[i+1] = temp
i+=1
swapped = True
elif swapped == False:
i += 1
elif swapped == True and i < n - 1:
i += 1
Note: In the example list (k), we only need to loop through the list three times in order for it to be sorted in ascending order. So if you change the while loop to this line of code while count < 4:, it would still work.

Categories

Resources