I can't figure out why the program is behaving in a peculiar way. The program is meant to rotate an array cyclically for 'K' times. When the list A is assigned to B in function rotate_array(), the program behaves in an incorrect way as shown in the output. Whereas when it is changed with the line B=[0]*len(A), the problem disappears. Could someone please help ?
def rotate_array(A):
#B = [0]*len(A) # This solves the problem
B = A # This seems to cause a problem
print "In rotate_array", A
for index, item in enumerate(A):
print "index:item ={}:{}, length of A={}".format(index, item, len(A))
if index == (len(A) - 1):
B[0] = A[index]
else:
B[index + 1] = item
print B
return B
def solution(A, K):
for index, item in enumerate(A):
print "in fn soln: index:item ={}:{}, length of A={}".format(index, item, len(A))
ctr = 0
while ctr < K:
A = rotate_array(A)
ctr += 1
return A
if __name__ == '__main__':
A = [1,2,3,4]
K = 1
ret_A = solution(A, K)
print ret_A
Output:
in fn soln: index:item =0:1, length of A=4
in fn soln: index:item =1:2, length of A=4
in fn soln: index:item =2:3, length of A=4
in fn soln: index:item =3:4, length of A=4
In rotate_array [1, 2, 3, 4]
index:item =0:1, length of A=4
index:item =1:1, length of A=4
index:item =2:1, length of A=4
index:item =3:1, length of A=4
[1, 1, 1, 1]
[1, 1, 1, 1]
When function rotate_array(A) is changed to have this line
B = [0]*len(A) # This solves the problem
instead of
B = A
The output is now correct -
in fn soln: index:item =0:1, length of A=4
in fn soln: index:item =1:2, length of A=4
in fn soln: index:item =2:3, length of A=4
in fn soln: index:item =3:4, length of A=4
In rotate_array [1, 2, 3, 4]
index:item =0:1, length of A=4
index:item =1:2, length of A=4
index:item =2:3, length of A=4
index:item =3:4, length of A=4
[4, 1, 2, 3]
[4, 1, 2, 3]
I see that John answered your question. I dont know all the details of what you are doing, so you may have a reason for looping, but I wanted to suggest an alternative implementation that didn't require looping K times if all you want is the final answer:
def rotate_array(A,K):
A_length = len(A)
B = [None] * A_length
for A_index in range(len(A)):
B_index = (A_index + K) % A_length
B[B_index] = A[A_index]
return(B)
A = list(range(10))
print("A = ", A)
for K in range(10):
B = rotate_array(A,K)
print("K = ",K, "B = ", B)
A = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
K = 0 B = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
K = 1 B = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8]
K = 2 B = [8, 9, 0, 1, 2, 3, 4, 5, 6, 7]
K = 3 B = [7, 8, 9, 0, 1, 2, 3, 4, 5, 6]
K = 4 B = [6, 7, 8, 9, 0, 1, 2, 3, 4, 5]
K = 5 B = [5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
K = 6 B = [4, 5, 6, 7, 8, 9, 0, 1, 2, 3]
K = 7 B = [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
K = 8 B = [2, 3, 4, 5, 6, 7, 8, 9, 0, 1]
K = 9 B = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
Related
Given that I have a list of numbers:
raw_list = [10, 9, 2, 8, 1, 3, 5, 4, 6, 7,11]
I want to separate it to top N's three times. Which means I want to rank them.
# Top 6 rank as 3
# Next Top 4 rank as 2
# Last Top 1 rank as 1
ranked_list = [3, 3, 2, 3, 1, 2, 2, 2, 3, 3, 3]
What I tried:
sorted(range(len(raw_list)), key=lambda i: raw_list[i])[-2:]
But this only gives indeces of the topmost and not the next topmost value of the list.
Use:
lst = [10, 9, 2, 8, 1, 3, 5, 4, 6, 7, 11]
indices = sorted(range(len(lst)), key=lambda i: lst[i], reverse=True)
ranked_list = [0 for _ in range(len(lst))]
for i, j in enumerate(indices):
if i < 6:
ranked_list[j] = 3
elif i < 6 + 4:
ranked_list[j] = 2
else:
ranked_list[j] = 1
print(ranked_list)
Output
[3, 3, 2, 3, 1, 2, 2, 2, 3, 3, 3]
Here's a different approach which is significantly faster than the accepted answer (if that's important):
Edited to show performance timings between the original and accepted answer because #funnydman wants proof
from timeit import timeit
L = [10, 9, 2, 8, 1, 3, 5, 4, 6, 7, 11]
def func1(list_):
slist = sorted(list_)
result = []
top6 = set(slist[5:])
top4 = set(slist[1:5])
for e in list_:
if e in top6:
result.append(3)
elif e in top4:
result.append(2)
else:
result.append(1)
return result
def func2(list_):
indices = sorted(range(len(list_)), key=lambda i: list_[i], reverse=True)
ranked_list = [0 for _ in range(len(list_))]
for i, j in enumerate(indices):
if i < 6:
ranked_list[j] = 3
elif i < 6 + 4:
ranked_list[j] = 2
else:
ranked_list[j] = 1
return ranked_list
for func in func1, func2:
print(func.__name__, timeit(lambda: func(L)))
Output:
func1 1.3904414890002954
func2 2.388311982000232
IIUC, this will work for you:
import pandas as pd
list(pd.cut(l, bins=[0, 1, 5, 11], labels=[1, 2, 3]))
Output:
[3, 3, 2, 3, 1, 2, 2, 2, 3, 3, 3]
In the following code, I call the Sort function two times with a different behavior but it returns the same results. In the advancedSort() function, I called Sort() function two times with different behavior (order) and saved each result in different lists but when I am printing the lists the results are the same!
def Sort(inputs, order = "ascending"):
if order == "ascending":
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] > inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
elif order == "decending":
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] < inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
else:
raise ValueError(order)
return inputs
def advancedSort(inputList, inputOrder):
if inputOrder == "ascending":
newList = Sort(inputList, "ascending")
return newList
elif inputOrder == "decending":
newList = Sort(inputList, "decending")
return newList
elif inputOrder == "both":
newList1 = Sort(inputList, "ascending")
newList2 = Sort(inputList, "decending")
return newList1, newList2
else:
raise ValueError(order)
a = [1, 4, 7, 7, 0, 6, 4]
print(a)
b, c = advancedSort(a, "both")
print(b)
print(c)
Output is:
[1, 4, 7, 7, 0, 6, 4]
[7, 7, 6, 4, 4, 1, 0]
[7, 7, 6, 4, 4, 1, 0]
When Sort() runs the first time it'll change the list referenced by a.
When you run it a second time, it's not using the original list you've defined in the beginning, but one already modified by Sort().
To address this you may use a shallow copy of the list:
newList1 = Sort(inputList.copy(), "ascending")
newList2 = Sort(inputList.copy(), "decending")
I used your code to print the memory address of each variable and their behavior in the routines:
def Sort(inputs, order = "ascending"):
if order == "ascending":
print(f"running the ascending routine with inputs = {inputs} ({hex(id(inputs))})")
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] > inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
elif order == "decending":
print(f"""running the decending routine with inputs = {inputs} ({hex(id(inputs))})""")
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] < inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
else:
raise ValueError(order)
return inputs
def advancedSort(inputList, inputOrder):
if inputOrder == "ascending":
newList = Sort(inputList, "ascending")
return newList
elif inputOrder == "decending":
newList = Sort(inputList, "decending")
return newList
elif inputOrder == "both":
newList1 = Sort(inputList, "ascending")
newList2 = Sort(inputList, "decending")
return newList1, newList2
elif inputOrder == "shallow":
newList1 = Sort(inputList.copy(), "ascending")
newList2 = Sort(inputList.copy(), "decending")
return newList1, newList2
else:
raise ValueError(order)
a = [1, 4, 7, 7, 0, 6, 4]
print(f"a = {a} ({hex(id(a))})")
print("\ntrying shallow mode")
b, c = advancedSort(a, "shallow")
print(f"b = {b} ({hex(id(b))})")
print(f"c = {c} ({hex(id(c))})")
print("\ntrying both mode")
d, e = advancedSort(a, "both")
print(f"a = {a} ({hex(id(a))})")
print(f"d = {d} ({hex(id(d))})")
print(f"e = {e} ({hex(id(e))})")
print("\nnow trying shallow mode again")
f, g = advancedSort(a, "shallow")
print(f"a = {a} ({hex(id(a))})")
print(f"f = {f} ({hex(id(f))})")
print(f"g = {g} ({hex(id(g))})")
Output:
a = [1, 4, 7, 7, 0, 6, 4] (0x7f4166c71240)
trying shallow mode
running the ascending routine with inputs = [1, 4, 7, 7, 0, 6, 4] (0x7f4166a535c0)
running the decending routine with inputs = [1, 4, 7, 7, 0, 6, 4] (0x7f4166ac8a80)
b = [0, 1, 4, 4, 6, 7, 7] (0x7f4166a535c0)
c = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac8a80)
trying both mode
running the ascending routine with inputs = [1, 4, 7, 7, 0, 6, 4] (0x7f4166c71240)
running the decending routine with inputs = [0, 1, 4, 4, 6, 7, 7] (0x7f4166c71240)
a = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
d = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
e = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
now trying shallow mode again
running the ascending routine with inputs = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac88c0)
running the decending routine with inputs = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac8780)
a = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
f = [0, 1, 4, 4, 6, 7, 7] (0x7f4166ac88c0)
g = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac8780)
I think, it is because your function Sort (by the way it is better to rename it with lowercase sort()) it is changing the value of the original list. So, when you call with "ascending" or "descending", there's no problem becuse you only order one time, but with "both" the newList2 = Sort(inputList, "decending") use an a list mutated.
You never must work with the original list, always clone it and make the changes in the clone it. To work:
def Sort(inputs, order = "ascending"):
cloned_list = inputs[:]
if order == "ascending":
for i in range(len(cloned_list)):
for j in range(i + 1, len(cloned_list)):
if cloned_list[i] > cloned_list[j]:
cloned_list[i], cloned_list[j] = cloned_list[j], cloned_list[i]
elif order == "decending":
for i in range(len(cloned_list)):
for j in range(i + 1, len(cloned_list)):
if cloned_list[i] < cloned_list[j]:
cloned_list[i], cloned_list[j] = cloned_list[j], cloned_list[i]
else:
raise ValueError(order)
return cloned_list
Output:
[1, 4, 7, 7, 0, 6, 4] # a
[0, 1, 4, 4, 6, 7, 7] # b
[7, 7, 6, 4, 4, 1, 0] # c
I have the following code
a = [1, 2, 3, 4, 5, 6]
b = [1, 3, 3, 4, 5, 7]
counter = 0
for x,y in tuple(zip(a, b)):
if x==y:
counter += 1
How do I write that in one line? I tried this counter+= 1 if ((x==y) for (x, y) in tuple(zip(a, b))) else None but it adds 1 to the counter and that's all.
You can leverage True == 1 and False == 0
>>> a = [1, 2, 3, 4, 5, 6]
>>> b = [1, 3, 3, 4, 5, 7]
>>> counter = sum(_a==_b for _a,_b in zip(a,b))
>>> counter
4
Addition over an iterable can be expressed with sum():
counter = sum(1 if x==y else 0 for x,y in zip(a, b))
you can try this,
a = [1, 2, 3, 4, 5, 6]
b = [1, 3, 3, 4, 5, 7]
counter=len([x for x,y in zip(a,b) if x==y])
Another way,
counter=sum(map(lambda x:x[0]==x[1],zip(a,b)))
The problem is regarding reversing a list A of size N in groups of K. For example if A = [1,2,3,4,5], k = 3
Output = [3,2,1,5,4]
The error I get, when I run this is List Index out of range on line 4.
def reverseInGroups(A,N,K):
arr1 = []
for i in range(K):
arr1.append(A[(N-i)%K]) #line 4
for j in range(N-K):
arr1.append(A[N-j-1])
return arr1
This will implement what you are trying to achieve:
def reverseInGroups(A,K):
N = len(A)
arr1 = []
for i in range(0, N, K):
arr1.extend(A[i : i+K][::-1])
return arr1
print(reverseInGroups([1,2,3,4,5], 3))
Interestingly, the code in the question actually works in the example case, but it is not general. The case where it works is where N = 2*K - 1 (although where it does not work, the elements are in the wrong order rather than an IndexError).
Cant seem to reproduce your 'List index out of range' error, but your logic is faulty:
reverseInGroups(A,N,K):
arr1 = []
for i in range(K):
arr1.append(A[(N-i)%K]) #line 4
for j in range(N-K):
arr1.append(A[N-j-1])
return arr1
print(reverseInGroups([1,2,3,4,5],5, 3)) # works, others get wrong result
print(reverseInGroups([1,2,3,4,5,6],6, 3)) # wrong result: [1, 3, 2, 6, 5, 4]
prints:
[3, 2, 1, 5, 4] # correct
[1, 3, 2, 6, 5, 4] # wrong
You fix this and make this smaller by packing it into a list comprehension:
def revv(L,k):
return [w for i in (L[s:s+k][::-1] for s in range(0,len(L),k)) for w in i]
for gr in range(2,8):
print(gr, revv([1,2,3,4,5,6,7,8,9,10,11],gr))
to get:
2 [2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 11]
3 [3, 2, 1, 6, 5, 4, 9, 8, 7, 11, 10]
4 [4, 3, 2, 1, 8, 7, 6, 5, 11, 10, 9]
5 [5, 4, 3, 2, 1, 10, 9, 8, 7, 6, 11]
6 [6, 5, 4, 3, 2, 1, 11, 10, 9, 8, 7]
7 [7, 6, 5, 4, 3, 2, 1, 11, 10, 9, 8]
You can also try with this:
def reverse(l, n):
result = []
for i in range(0, len(l)-1, n):
for item in reversed(l[i:i+n]):
result.append(item)
for item in reversed(l[i+n:]):
result.append(item)
return result
You can reverse the array upto index K and reverse the remaining part and add these both arrays.
def reverseInGroups(A,N,K):
return A[:K][::-1]+A[K:][::-1]
A = [1,2,3,4,5]
N = 5
K = 3
res = reverseInGroups(A,N,K)
print(res)
def heap_sort(nos):
global size
size = len(nos)
print "the size of the List is : %d " %size
Build_heap(size,nos)
for i in range(size-1,0,-1):
nums[0],nums[i] = nums[i],nums[0]
size = size-1
print "\n", nums
heapify(nos,i,size)
print "heap sort array:" ,nums
def left_child(i):
return 2*i+1
def right_child(i):
return 2*i+2
def heapify(nums,i,size):
l = left_child(i)
r = right_child(i)
if l <= size and r <= size:
if r != size:
if nums[l] >= nums[r]:
max = nums[l]
max_index = l
elif nums[l] <= nums[r]:
max = nums[r]
max_index = r
if nums[i] >= max:
print nums
return
elif nums[i] <= max:
nums[i],nums[max_index] = max,nums[i]
heapify(nums,max_index,size)
else:
nums[i],nums[l] = nums[l],nums[i]
print nums
# build a heap A from an unsorted array
def Build_heap(size,elements):
iterate = size//2-1
for i in range(iterate,-1,-1):
print "In %d iteration" %i
heapify(elements,i,size)
print "heapified array is : " ,elements
if __name__ == '__main__':
#get input from user
nums = [6,9,3,2,4,1,7,5,10]
#sort the list
heap_sort(nums)
Output which I get is something like this:
the size of the List is : 9
In 3 iteration
[6, 9, 3, 10, 4, 1, 7, 5, 2]
In 2 iteration
[6, 9, 7, 10, 4, 1, 3, 5, 2]
In 1 iteration
[6, 10, 7, 9, 4, 1, 3, 5, 2]
[6, 10, 7, 9, 4, 1, 3, 5, 2]
In 0 iteration
[10, 6, 7, 9, 4, 1, 3, 5, 2]
[10, 9, 7, 6, 4, 1, 3, 5, 2]
[10, 9, 7, 6, 4, 1, 3, 5, 2]
heapified array is : [10, 9, 7, 6, 4, 1, 3, 5, 2]
heap sort array:
[9, 7, 6, 4, 1, 3, 5, 2, 10]
I tried implementing a heap sort algorithm in python. The final output is not sorted. There is something wrong in the heapify operation which I tried to figure out, but I couldn't find it.
Can someone point out what's wrong in my code and propose a solution for it?
The first item(0) was swaped with the last item. To keep max-heap invairant, you should call heapify with 0.
def heap_sort(nos):
size = len(nos)
build_heap(size,nos)
for i in range(size-1,0,-1):
nums[0],nums[i] = nums[i],nums[0]
size -= 1
heapify(nos, 0, size) # <--- i -> 0
The following is my PYTHON implementation. If the program is "heapsort.py", an example to run it is "python heapsort.py 10", to sort 10 randomly generated numbers.
The validation code is near the end of the program, to verify the correctness of the function, heapsort().
#!/bin/python
#
# TH #stackoverflow, 2016-01-20, HeapSort
#
import sys, random
def pushdown( A, root, size_of_A ):
M = root * 2
if(M <= size_of_A):
if(size_of_A > M):
if(A[M - 1] < A[M]):
M += 1
if(A[root - 1] < A[M - 1]):
A[root - 1], A[M - 1] = A[M - 1], A[root - 1]
pushdown(A, M, size_of_A)
def heapsort( H ):
for i in range(len(H)/2, 0, -1):
pushdown(H, i, len(H))
for i in range(len(H) - 1, 0, -1):
H[i], H[0] = H[0], H[i]
pushdown(H, 1, i)
return H
number_to_numbers = int(sys.argv[1])
X = [ random.randint(0, number_to_numbers) for i in range(number_to_numbers) ]
Y = X
print Y
print heapsort(X)
print sorted(Y)