I have two lists of equal length: a and b. List b contains several of the same floating point numbers as list a at the same indices, but the other indices are replaced with zeros. These lists also contain several thousand values each.
I would like to iterate through list b until it gets to a non-zero value then iterate through list a from the same index until a greater value is reached. I want to then append that greater value to an empty list and then continue to iterate through list b until the next non-zero value and repeat.
c=[]
i = 0
j = 0
while i < len(a):
if b[i] == 0:
i = i + 1
if b[i] > 0:
j = i
if a[j] < b[i]:
j = j + 1
if a[j] == b[i]:
j = j + 1
if a[j] > b[i]:
c.append(a[j])
i = i + 1
I have tried multiple ways to do this with for and while loops and either end up just appending the whole of list a into the empty list or I create an infinite while loop, so any help or advice on how to get started would be greatly appreciated!
Incorporating #MichaelButscher's answer into this and adding another list d that contains dates that correspond to the values in lists a and b, I then appended the dates for the values that met the condition if a[j] > b[i]: into a new list e.
d=['05/01/2000','06/01/2000','07/01/2000','10/01/2000','11/01/2000','12/01/2000','23/10/2000','24/10/2000','25/10/2000','13/12/2000','14/12/2000','15/12/2000','20/02/2001','21/02/2001','21/09/2001','19/06/2002','20/06/2002']
a=[1.86,1.85,1.89,1.82,1.82,1.83,1.846,1.898,1.869,1.923,1.926,1.9677,1.959,2.02,2.802,2.7312,2.8035]
b=[0,0,1.89,0,0,0,0,0,0,0,0,1.9677,0,0,2.802,0,0]
c=[]
e=[]
i = 0
j = 0
# Run until break
while True:
while i < len(a):
if b[i] != 0:
break # break inner while
i += 1
else:
break # break outer while
# At this point: i < len(a) and b[i] != 0
j = i
while j < len(a):
if a[j] > b[i]:
# At this point: i < len(a) and b[i] != 0 and j < len(a) and a[j] > b[i]
c.append(a[j])
e.append(d[j])
break
j += 1
# At this point either appropriate j was found or j == len(a)
# Anyway, next i to check
i += 1
lists c and e were then printed in columns:
24/10/2000 1.898
24/10/2000 1.898
21/02/2001 2.02
10/09/2001 2.606
20/06/2002 2.8035
24/09/2002 3.8132
22/09/2015 4.0667
04/09/2015 3.853
01/09/2015 3.7031
10/05/2004 3.148
Some of the data is repeated and isn't in ascending date order even though the dates in list d were.
This can be done by nesting while loops. Outer while just runs forever (until break) inner while loops check for desired state.
Untested but should work:
c=[]
i = 0
j = 0
# Run until break
while True:
while i < len(a):
if b[i] != 0:
break # break inner while
i += 1
else:
break # break outer while
# At this point: i < len(a) and b[i] != 0
j = i
while j < len(a):
if a[j] > b[i]:
# At this point: i < len(a) and b[i] != 0 and j < len(a) and a[j] > b[i]
c.append(a[j])
break
j += 1
# At this point either appropriate j was found or j == len(a)
# Anyway, next i to check
i += 1
Related
It takes the random list I generated but the output is something a lot different than I expected.
I think that something goes wrong with merging.
e.g. : Input --> [267,168,236,190,2,500,4,45,86]
Output --> [2,2,2,2,2,4,4,4,45,45,86]
Thank you in advance.
import numpy as np
def mergeSort(myList):
if len(myList) > 1:
mid = len(myList) // 2
left = myList[:mid]
right = myList[mid:]
# Recursive call on each half
mergeSort(left)
mergeSort(right)
# Two iterators for traversing the two halves
i = 0
j = 0
# Iterator for the main list
k = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
# The value from the left half has been used
myList[k] = left[i]
# Move the iterator forward
i += 1
else:
myList[k] = right[j]
j += 1
# Move to the next slot
k += 1
# For all the remaining values
while i < len(left):
myList[k] = left[i]
i += 1
k += 1
while j < len(right):
myList[k]=right[j]
j += 1
k += 1
list1 = np.random.randint(low=1, high=800, size=100)
myList = list1
print("Given array is", end="\n")
print(myList)
mergeSort(myList)
print("Sorted array is: ", end="\n")
print(myList)
The problem with your code is only with inplace manipulation of your original list. merge sort needs extra space O(n).
you could simply rewrite your code like this to work: (notice that it is your code, only I modified two lines, look for # changed ...)
import numpy as np
def mergeSort(myList):
if len(myList) > 1:
mid = len(myList) // 2
left = myList[:mid].copy() # changed this line
right = myList[mid:].copy() # changed this line
# Recursive call on each half
mergeSort(left)
mergeSort(right)
# Two iterators for traversing the two halves
i = 0
j = 0
# Iterator for the main list
k = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
# The value from the left half has been used
myList[k] = left[i]
# Move the iterator forward
i += 1
else:
myList[k] = right[j]
j += 1
# Move to the next slot
k += 1
# For all the remaining values
while i < len(left):
myList[k] = left[i]
i += 1
k += 1
while j < len(right):
myList[k]=right[j]
j += 1
k += 1
myList = np.random.randint(low=1, high=800, size=100)
print("Given array is", end="\n")
print(myList)
mergeSort(myList)
print("Sorted array is: ", end="\n")
print(myList)
However this is not very optimized version of implementation for the mergsort specially in python.
Here is better implementation, pure python (from: https://github.com/amirhm/algo-data-scratch/blob/main/Sorting/mergesort.ipynb)
def mergesort(l):
def merge(l, r):
lp, rp = 0 , 0
d = []
while lp < len(l) and rp < len(r):
if l[lp] < r[rp]:
d.append(l[lp])
lp += 1
else:
d.append(r[rp])
rp += 1
if rp < len(r): d.extend(l[lp:])
if lp < len(l): d.extend(r[rp:])
return d
if len(l) <= 1:
return l
n = len(l)
return merge(mergesort(l[:n//2]), mergesort(l[n//2:]))
or much more abstract only in 9 lines:
def mergesort(l):
def merge(l, r):
res = []
while l and r : ((res.append(l.pop())) if (l[-1] > r[-1]) else res.append(r.pop()))
#while r or l: res.append(r.pop()) if r else (res.append(l.pop()))
if r: res[::-1].extend(r)
if l: res[::-1].extend(l)
return res
if len(l) <= 1: return l
return merge(mergesort(l[:len(l) // 2]), mergesort(l[len(l) // 2:]))
I want to check that my understanding of how python handles slices is correct.
Here's my implementation of merge sort:
def merge_sort(L):
def merge(a, b):
i, j = 0, 0
c = []
while i < len(a) and j < len(b):
if a[i] < b[j]:
c.append(a[i])
i += 1
elif b[j] < a[i]:
c.append(b[j])
j += 1
if a[i:]:
c.extend(a[i:])
if b[j:]:
c.extend(b[j:])
return c
if len(L) <= 1:
return L
else:
mid = len(L) // 2
left = merge_sort(L[:mid])
right = merge_sort(L[mid:])
return merge(left, right)
Am I right in thinking that I could replace this:
if a[i:]:
c.extend(a[i:])
if b[j:]:
c.extend(b[j:])
With this:
while i < len(a):
c.append(a[i])
i += 1
while j < len(b):
c.append(b[j])
j += 1
And have the exact same level of complexity? My understanding of slicing is that its complexity is equivalent to slice length? Is that correct?
Does the fact that I'm calling a slice twice (first in the condition, second time inside of it) make it 2x complexity?
Your implementation of mergesort has problems:
in the merge function's main loop, you do nothing if the values in a[i] and b[j] are equal, or more precisely if you have neither a[i] < b[i] nor a[i] > b[i]. This causes an infinite loop.
there is no need to define merge as a local function, actually there is no need to make it a separate function, you could inline the code and save the overhead of a function call.
Here is a modified version:
def merge_sort(L):
if len(L) <= 1:
return L
else:
mid = len(L) // 2
a = merge_sort(L[:mid])
b = merge_sort(L[mid:])
i, j = 0, 0
c = []
while i < len(a) and j < len(b):
if a[i] <= b[j]:
c.append(a[i])
i += 1
else:
c.append(b[j])
j += 1
if a[i:]:
c.extend(a[i:])
else:
c.extend(b[j:])
return c
Regarding performance, slicing or iterating has no impact on complexity since both operations have linear time cost.
Regarding performance, here are directions to try:
replace the test if a[i:] with if i < len(a). Creating the slice twice is costly.
perform the sort in place, avoiding the append operations
restructure the main loop to have a single test per iteration
Here is a modified version:
def merge_sort(L):
if len(L) <= 1:
return L
else:
mid = len(L) // 2
a = merge_sort(L[:mid])
b = merge_sort(L[mid:])
i, j, k = 0, 0, 0
while True:
if a[i] <= b[j]:
L[k] = a[i]
k += 1
i += 1
if (i == len(a)):
L[k:] = b[j:]
return L
else:
L[k] = b[j]
k += 1
j += 1
if (j == len(b)):
L[k:] = a[i:]
return L
I'm working on a code challenge in which I have to reduce the execution time as much as possible, the only thing I able to find where I can make an improvement is a nested if-else statement inside a nested for-loop but I'm not sure how it can be improvided.
Here's my code:
mat = [[0] * n] * n
count = 0
for i in range(n,0,-1):
count += 1
for j in range(i,n+1,1):
if i == j:
pass
else:
if getEnemyStatus(mat, i, j):
break
else:
if isEnemy(enemyDict, i, j):
setStatus(mat, i, j)
break
else:
count += 1
value of n can be from 1 to 10^5
You can skip the first if condition by starting with i+1 in range
for j in range(i+1, n+1, 1):
# code here
Second, nested if else condition should be avoided with elif for reading purpose.
Update code should be like:
mat = [[0] * n] * n
count = 0
for i in range(n,0,-1):
count += 1
for j in range(i + 1, n + 1, 1):
if getEnemyStatus(mat, i, j):
break
elif isEnemy(enemyDict, i, j):
setStatus(mat, i, j)
break
else:
count += 1
NOTE: Also if you can set the status setStatus in your isEnemy function then you can get more cleaner code:
mat = [[0] * n] * n
count = 0
for i in range(n,0,-1):
count += 1
for j in range(i + 1, n + 1, 1):
if getEnemyStatus(mat, i, j) or isEnemy(enemyDict, i, j):
break
count += 1
Q- I have an array A with the sizes of apples and have to create another array S which would contain the indices of the apples in sorted order given that we cannot directly access or touch A only a function is_large(A,i,j) function can access it. It returns -1 is A[i] > A[j] and 1 if A[i] < A[j].
I wrote the program but it is giving incorrect results even for small arrays what is the problem? The main problem is that the first element is not changing positions because of that the whole array is unsorted.
def is_large_apples(apple_size, i, j):
""" Takes two indices and tells
which one of them is larger or smaller """
if apple_size[i] > apple_size[j]:
return 1
elif apple_size[i] < apple_size[j]:
return -1
def mergesort_apples(s, l, r):
""" This function takes indexed list and
makes recursive calls to sort the array """
if l < r:
mid = (l+r)//2
mergesort_apples(s, l, mid)
mergesort_apples(s, mid+1, r)
merge_apples(s, l, mid, r)
def merge_apples(s, l, mid, r):
""" This function takes the list and
the indices to merge them into the final array"""
nl = mid - l + 1
nr = r - mid
left, right = [], []
left = s[l:mid+1:1]
right = s[mid+1:r+1:1]
i, j, k = 0, 0, l;
while i < nl and j < nr:
print(s)
if is_large_apples(apple_size, i, j) == -1:
s[k] = left[i]
i += 1
else:
s[k] = right[j]
j += 1
k += 1
while i < nl:
s[k] = left[i]
k += 1
i += 1
while j < nr:
s[k] = right[j]
k += 1
j += 1
apple_size = [5, 7, 1,44,2,33] # Given list of sizes.
s = [x for x in range(0,len(apple_size))] # Original list of indices.
mergesort_apples(s, 0, len(s)-1)
print(s)
if is_large_apples(apple_size, left[i], right[j]) == -1:
Because you want to check not i and j position, but left[i] position and right[j] position.
I am trying to apply a stress test on python maximum pairwise product, fast and slow algorithm. However, The fast code appears to return a wrong result in some tests. I think the problem comes from the if condition in the fast algorithm. The condition doesn't occur in some cases, though it should be applies. I wasn't able to figure out the problem. any help?
Here is the problem, I/P, O/P details:
Given a sequence of non-negative integers a0,…,an−1, find the maximum pairwise product, that is, the largest integer that can be obtained by multiplying two different elements from the sequence (or, more formally, max0≤i≠j≤n−1aiaj). Different elements here mean ai and aj with i≠j (it can be the case that ai=aj).
Input format
The first line of the input contains an integer n. The next line contains n non-negative integers a0,…,an−1 (separated by spaces).
Constraints:
2≤n≤2⋅105; 0≤a0,…,an−1≤105.
Output format:
Output a single number — the maximum pairwise product.
from random import randint
from random import randrange
def max_pairwise(n,a):
# n = int(input())
res = 0
# a = [int(x) for x in input().split()]
assert(len(a) == n)
for i in range(0,n):
for j in range(i+1,n):
if a[i]*a[j] > res:
res = a[i]*a[j]
return(res)
def max_pairwise_fast(n,a):
# n = int(input())
# a = [int(x) for x in input().split()]
max_index1 = -1
max_index2 = -1
for i in range(0,n):
if a[i] > a[max_index1]:
max_index1 = i
else:
continue
for j in range(0,n):
if ((a[j] != a[max_index1]) and (a[j] > a[max_index2])):
max_index2 = j
else:
continue
res = a[max_index1]* a[max_index2]
return(res)
#stress_test
while(1):
n = randint(0,9) +2
print(n,"n")
a = []
for i in range (n):
a.append(randrange(9000))
for i in range(n):
print(a[i],'a[i]',"/n")
if (max_pairwise(n,a) == max_pairwise_fast(n,a)):
print(max_pairwise(n,a), max_pairwise_fast(n,a),"true")
else:
print(max_pairwise(n,a), max_pairwise_fast(n,a), "false")
break
This is an example of the result:
6 n
318 a[i] /n
7554 a[i] /n
7531 a[i] /n
7362 a[i] /n
4783 a[i] /n
4897 a[i] /n
56889174 56889174 true
5 n
6879 a[i] /n
6985 a[i] /n
8561 a[i] /n
5605 a[i] /n
3077 a[i] /n
59798585 59798585 true
9 n
8285 a[i] /n
3471 a[i] /n
2280 a[i] /n
2443 a[i] /n
5437 a[i] /n
2605 a[i] /n
1254 a[i] /n
6990 a[i] /n
2943 a[i] /n
57912150 68641225 false
In your fast implementation, when you are finding a largest number, you must also update the second largest to the value of the previous largest, otherwise, there are cases where you end up multiplying numbers that are not the two largest.
def product_of_two_largest(seq):
largest = float("-inf")
second_largest = float("-inf")
for elt in seq:
if elt > largest:
second_largest = largest
largest = elt
elif elt > second_largest:
second_largest = elt
return second_largest * largest
Note 1:
Your while loop must also be updated, you are calculating the values twice instead of once.
while(1):
n = randint(0,9) +2
print(n,"n")
a = []
for i in range (n):
a.append(randrange(9000))
for i in range(n):
print(a[i],'a[i]',"/n")
slow, fast = max_pairwise(n, a), two_largest_product(a)
if (slow == fast):
print(slow, fast, slow == fast)
else: # attention, this never happens now.
break
Note 2:
As we are dealing with only non-negative integers, you will likely have a faster implementation if you simply sort the sequence and multiply the last two numbers (in spite of the fact that sort is O(nlogn), vs O(n) for the fast implementation above.
b = sorted(a)
print("max1 x max2 = ", b[-1] * b[-2])
Note 3:
Using a heap data structure (from collections import heap) is the theoretical best way to find the n largest items, but you'd likely need to have 100,000's of items to make it worth your while.
def max_pairwise_fast(n, a):
max_index1 = 0
max_index2 = 0
for i in range(n):
if a[i] > max_index1:
max_index2 = max_index1
max_index1 = a[I]
elif a[i] > max_index2:
max_index2 = a[I]
return max_index1 * max_index2
if __name__ == '__main__':
input_n = int(input())
input_numbers = [int(x) for x in input().split()]
print(max_pairwise_fast(input_n, input_numbers))
This might not help you.
I was attempting this question at Coursera ( Assignment ) and found that we don't need to make the solution more complex. We can simply store the first two largest integers while scanning from the user and print their product. A complex solution is the main reason for the TLE error.
code in c
#include<stdio.h>
int main() {
long long n, a = 0, b = 0, i = 0, numb = 1;
scanf("%lld", &n);
for (i = 0; i < n; i++){
scanf("%lld", &numb);
if(numb >= a){
b = a;
a = numb;
}
else if(numb > b)
b = numb;
}
printf("%lld", a * b);
return 0;
}
With input array data:
Example: [1, 2, 3]
def max(arr):
a = 0
b = 0
for i in range(len(arr)):
if a == 0 & arr[i]>a:
a = arr[i]
else:
if arr[i]>a:
b = a
a = arr[i]
else:
if arr[i]>b:
b = arr[i]
return a*b;
def max_pairwise_fast(n, a):
max_index1 = 0
max_index2 = 0
for i in range(n):
if a[i] > max_index1:
max_index2 = max_index1
max_index1 = a[i]
elif a[i] > max_index2:
max_index2 = a[i]
return max_index1 * max_index2
if __name__ == '__main__':
input_n = int(input())
input_numbers = [int(x) for x in input().split()]
print(max_pairwise_fast(input_n, input_numbers))