Selection Sort in Python not sorting - python-3.x

I wrote a program for selection sort by first creating a function that finds the minimum element in the array. Then I iterate through the array placing the smallest element in the correct place in the array while replacing the smallest element.
This is my code :
a=[int(input()) for _ in range(6)]
def smallest_element(arr,x):
smallest = arr[x]
d = x
for j in range(x+1,len(arr)):
if arr[j] < smallest:
smallest = arr[j]
d = j
return d
for i in range(0,len(a)):
c = a[i]
if(c > a[smallest_element(a,i)]):
a[i] = a[smallest_element(a,i)]
a[smallest_element(a,i)] = c
print(a)
But the problem is my array is not getting sorted.
Input - [5,2,4,6,1,3]
Output - [5,2,4,6,1,3]

The error seems to be in your loop.
You assign the smallest value found to the current index.
a[i] = a[smallest_element(a,i)]
You then assign the value that was originally stored to the index where the smallest element is located.
a[smallest_element(a,i)] = c
You do however re-calculate the index of the smallest element, which always is the current index - because you just copied the smallest value to the current index.
first approach
I know of two solutions to this problem. First you may only search the index of the smallest element once per loop round. That way you do not re-calculate the index and write to the correct position.
for i in range(0, len(a)):
c = a[i]
indexOfSmallestElement = smallest_element(a, i)
smallestElement = a[indexOfSmallestElement]
if c > smallestElement:
a[i] = smallestElement
a[indexOfSmallestElement] = c
second approach
Another solution is to search the element starting from the current index + 1 instead of the current index, and thus skipping the entry that you've already changed.
Exchange a[smallest_element(a, i)] = c with a[smallest_element(a, i + 1)] = c.
I do however recommend to use the first approach as it recudes the amount of times the array is iterated over.

First, in your code, you have called the smallest_element(arr,x) 3 times which will consume more time for larger arrays. Instead we can store that value to a variable rather calling 3 times.
Secondly you are swapping 2 times one in function body and in if block.
So in the function body , find the current smallest element. Then return that index to main.Then if it is smaller than the present element (in the main for loop), then swap it.
#Find the smallest element
def smallest_element(arr,x):
small = x
for j in range(x+1,len(arr)):
if arr[j] < arr[small]:
small=j
return small
#now compare it with the current element
for i in range(0,len(a)):
c = a[i]
curr=smallest_element(a,i)
if(c > a[curr] and curr!=i):
a[i] = a[curr]
a[curr] = c
print(a)

Related

Array sorting timing out for huge size of arrays

I am doing an online code challenge. I have an array which I need to sort and record to minimum number of iterations required to be sorted. I have the following code.
def minSwap(ar):
c = 0
for i in range(0, len(ar)):
if ar[i] == i+1:
continue
else:
for k in range(i+1, len(ar)):
if ar[k] == i+1:
ar[k] = ar[i]
ar[i] = i+1
c = c+1
break
return c
This code passes majority of test cases, however for really huge number of case such as where array size is beyond (let's say 50000) it gets timeout.
How can I identify the faulty block of code? I can't see a way to tweak it further.
Looking at the problem statement, it looks like you want to sort a list that has numbers starting from 1 thru n.
If you are trying to sort the list, and the final list is expected to be [1, 2, 3, 4, 5, 6, 7 , 8, .....], then all you need to do is to insert the i+1 to the current position and pop the value of i+1 from its current position. That will reduce the number of iterations you need to sort or swap.
Here's the code that does this with least number of moves. At least that's what I found based on my tests.
def minSwap(ar):
c=0
for i in range(0, len(ar)):
if ar[i] != i+1:
#find the value of i+1 from i+1th position
temp = ar.index(i+1,i+1)
ar.insert(i,i+1) #insert i+1 in the ith position
ar.pop(temp+1) #remove the value of i+1 from the right
c+=1 #every time you do a swap, increment the counter
print (ar) #if you want to check if ar is correct, use this print stmt
return c
a = [1,3,4,5,6,7,2,8]
print (minSwap(a))
The total number of swaps for the above example is 1. It just inserts 2 in the second place and pops out 2 from position 6.
I ran the code for a = [1,6,5,4,3,8,2,7] and it swapped in 5 moves.
I ran the code for a = [1,3,5,4,6,8,2,7] and it swapped in 3 moves.
If you are trying to figure out how this works, use a print statement right after the if statement. It will tell you the element being swapped.
From your code I take it that sorting isn't the issue here, since you know you'll end up with ar[i] == i+1. Given that, why not change your else block to swap the current element into its slot, and repeat until you ar[i] is correct.
else:
while ar[i] != i+1:
temp = ar[i]
ar[i] = ar[temp - 1]
ar[temp - 1] = temp
You don't actually need to do a sort on this array. You just need to figure out the minimum number of swaps needed. If we just look at the following pattern, we can form a hypothesis to be tested:
1234 = 0
1324 = 1, swap 2 and 3
1423 = 2, swap 2 and 4, swap 3 and 4
4213 = 2, swap 1 and 4, swap 3 and 4
4123 = 3, swap 4 and 1, swap 4 and 2, swap 4 and 3
Based on these observations, I think we can work on the hypothesis that the answer will be max(0, n - 1) where n is the count of the number of "out of place" elements.
Then the code becomes simplified to:
def minSwap(ar):
c = 0
for i in range(0, len(ar)):
if ar[i] != i+1:
c = c + 1
return c < 0 ? 0 : c
Note that I don't actually know python so don't know if that last ternary is valid in python.

IndexError: list index out of range while using nested loops

A = [34,23,1,24,75,33,54,8]
K = 60
solution=[]
for i in range(len(A)):
for j in range(i+1,len(A)):
v=solution[(A[i]+A[j])]
print(v)
Hi, I am trying to get the list with result of individual sums like: 34+23 34+1 34+24 and so on then next 23+1,23+24 and so on.
Your code fails since it's trying to set v to the (A[i]+A[j])th element of solution, which is empty, so that value doesn't exist.
If I understand what you're trying to do, then this should give the desired result.
A = [34,23,1,24,75,33,54,8]
v = [[A[x] + A[i] for i in range(x + 1, len(A))] for x in range(len(A))]
As you can see here,
List index starts from 0 to the (n-1), where n is the len(list).
So A(len(A)) doesn't exist. Which results in the error.
So to fix this replace
len(A)
by
len(A) - 1
inside all instances of range function.

choose one list. choose the one whose nth element is the smallest. Python 3

I have two lists. I have to choose one. I have to choose the one with the smallest nth element. So I can choose the smallest element easy with min, but how do I back track it to the list itself. Have literally no idea how to solve this presumably easy problem.
a = [2,45,1,56]
b= [0,23,3,87]
Which list has the smallest element at position 2? The answer here is list a.
In case I wasnt clear, the program sould be able to solve this task for any pair of lists.
Here is a very simple snippet that does what you want, but you might want to check for the size of the arrays, in case the index is out of range.
def choose_smallest(a, b, i):
if len(a) >= i or len(b) >= i:
return 0 # do whatever you want here
if a[i] < b[i]:
return a
else:
return b
Also notice that both nth elements in your array can have the exact same value... In this example array b will be returned, but you can change that behaviour if needed.
EDIT
Added array length check
According to your example, here is a sample code you can try. You can change the code as per your requirement.
a = [2,45,1,56]
b = [0,23,3,87]
n= int(input('Enter element number: ')) # n starts from zero to length of list - 1
if a[n] > b[n]:
print('List b has smaller nth element')
elif a[n] < b[n]:
print('List a has smaller nth element')
else:
print('Both lists have equal nth element')

How to apply multiprocessing in python3.x for the following nested loop

for i in range(1,row):
for j in range(1,col):
if i > j and i != j:
x = Aglo[0][i][0]
y = Aglo[j][0][0]
Aglo[j][i] = offset.myfun(x,y)
Aglo[i][j] = Aglo[j][i]
Aglo[][] is a 2D array, which consists of lists in the first row
offset.myfun() is a function defined elsewhere
This might be a trivial question but i couldn't understand how to use multiprocessing for these nested loops as x,y (used in myfun()) is different for each process(if multiprocessing is used)
Thank you
If I'm reading your code right, you are not overwriting any previously calculated values. If that's true, then you can use multiprocessing. If not, then you can't guarantee that the results from multiprocessing will be in the correct order.
To use something like multiprocessing.Pool, you would need to gather all valid (x, y) pairs to pass to offset.myfun(). Something like this might work (untested):
pairs = [(i, j, Aglo[0][i][0], Aglo[j][0][0]) for i in range(1, row) for j in range(1, col) if i > j and i != j]
# offset.myfun now needs to take a tuple instead of x, y
# it additionally needs to emit i and j in addition to the return value
# e.g. (i, j, result)
p = Pool(4)
results = p.map(offset.myfun, pairs)
# fill in Aglo with the results
for pair in pairs:
i, j, value = pair
Aglo[i][j] = value
Aglo[j][i] = value
You will need to pass in i and j to offset.myfun because otherwise there is no way to know which result goes where. offset.myfun should then return i and j along with the result so you can fill in Aglo appropriately. Hope this helps.

For loops python that have a range

So I'm writing a python code and I want to have a for loop that counts from the the 2nd item(at increment 1). The purpose of that is to compare if there are any elements in the list that match or are included in the first element.
Here's what I've got so far:
tempStr = list500[0]
for item in list500(1,len(list500)):
if(tempStr in item):
numWrong = numWrong - 1
amount540 = amount540 - 1
However the code doesn't work because the range option doesn't work for lists. Is there a way to use range for a list in a for loop?
You can get a subset of the list with the code below.
tempStr = list500[0]
for item in list500[1:]:
if(tempStr in item):
numWrong = numWrong - 1
amount540 = amount540 - 1
The [1:] tells Python to use all elements of the array except for the first element. This answer has more information on list slicing.
Use a function:
search_linear(mainValues, target)
This is the algorithm you are looking for: http://en.wikipedia.org/wiki/Linear_search
All you need to do is set the starting point equal to +1 in order to skip your first index, and than use array[0] to call your first index as the target value.
def search_linear(MainValues, Target):
result = []
for w in Target:
if (search_linear(MainValues, w) < 0):
result.append(w)
return result

Resources