Deleting element in a python list iterated by index - python

folks
i have the following code:
for i in range(len(self.corpses)):
for j in range(len(self.corpses))[i+1:]:
if self.corpses[i].collides(self.corpses[j]):
self.corpses[i] = self.corpses[i] + self.corpses[j]
self.corpses.remove(self.corpses[j])
but this keeps going out of index.I would like to know what I do to remove the corpse under those conditions.
Thanks in advance.

You changed the length of the list. You could use a while loop instead:
i, l = 0, len(self.corpses)
while i < l:
j = i + 1
while j < l:
if self.corpses[i].collides(self.corpses[j]):
self.corpses[i] = self.corpses[i] + self.corpses[j]
del self.corpses[j]
l -= 1
else:
j += 1
i += 1
This way you keep full control over all changes.

Related

MergeSort in python

def merge(A,l,m,r):
i = l
j = m+1
new = []
while i <= m and j <= r:
if A[i] <= A[j]:
new.append(A[i])
i += 1
else:
new.append(A[j])
j += 1
while i <= m:
new.append(A[i])
i += 1
while j <= r:
new.append(A[j])
j += 1
return new
This function doesn't work due to an error, can you help me to understand what is the error and how to fix it?
This statement doesn't make sense:
return new
Since you nowhere use the return of the function. So the function merge() does nothing.
I believe you need to change the array A directly inside the function. No need to create and return the new array.

Write this pseudocode in python

I am trying to convert this pseudocode into python code
1 for j = 2 to A.length
2 i=1
3 while A[j]>A[i]
4 i = i+1
5 key = A[j]
6 for k = to j -i - 1
7 A[j-k] = A[j-k-1]
8 A[i] = key
The program says that i have to take 10 inputs and display it in the sorted array using Insertion sort algorithm Here's what i done at the moment i'm stuck at line 6 how do i convert that to python code
A= [int(i) for i in input ('Enter Number').spilt()]
for j in range(2, len(A)):
i = 1:
while A[j] > A[i]:
i = i+1
key = A[j]
for:#?
A[j-k] = A[j-k-1]
A[i] = key
First of all there is something missing in that line 6:
for k = to j -i - 1
It should read:
for k = 0 to j - i - 1
There are a few things to bear in mind when converting to Python:
In Python the first list element is at index 0, not index 1 as is the case in that pseudo code. So that means you need to subtract one at several places (where it concerns i and j).
Similarly, the range function's second argument (the "end" of the range) is a value that is not included in the range, while in the pseudo code, what follows to is included.
So here is how you could translate the code:
A= [int(i) for i in input ('Enter Number').split()]
for j in range(1, len(A)):
i = 0 # zero-based index
while A[j] > A[i]:
i = i+1
key = A[j]
for k in range(0, j-i):
A[j-k] = A[j-k-1]
A[i] = key
As stated in comments, the loop on k seems overly complex. It could just be:
for k in range(j, i, -1):
A[k] = A[k-1]
And a bit more pythonic would be to replace that for loop with:
A[i+1:j+1] = A[i:j]
Finally, the outer loop can take the index and value (key) with enumerate, which saves a few repetitive list look-ups in the form of A[j]:
for j, key in enumerate(A):
i = 0
while val > A[i]:
i = i+1
A[i+1:j+1] = A[i:j]
A[i] = key
With this for loop, you get one more iteration (with j == 0) which does nothing really, so you may decide to use the original loop.

How to fix an 'index out of range' error in Python?

I would like to write en auxiliar function which is counting the occurences of every integer between 0 and li[-1], saying that li is a sorted list.
I can't see my mistake... I know what this kind of error message means, but I don't know where the variable j is reaching a limit.
def aux_compter_occurence(li):
resu = [0] * (li[-1]+1)
i = 0
j = 0
while i < (li[-1] + 1):
while li[j] == i:
resu[i] += 1
j +=1
i += 1
return resu
For example, with the input [2,4,4,4,7,8,8], the output should be [0,0,1,0,3,0,0,1,2]
collections.Counter can be passed an iteratable and will count each occurance, we can then use a simple comprehension to generate the result
import collections
def aux_compter_occurence(li):
counts = collections.Counter(li)
return [counts.get(i, 0) for i in range(li[-1] + 1)]
Or if you wish to use the previous method of incrementing the values in a list, you already know the index in the list because it is equal to the integer value. We can simplify quite a bit
def aux_compter_occurence(li):
resu = [0] * (li[-1] + 1)
for i in li:
resu[i] += 1
return resu
I added "j < len(li)" to your code and now it works.
def aux_compter_occurence(li):
resu = [0] * (li[-1]+1)
i = 0
j = 0
while i < (li[-1] + 1):
while j < len(li) and li[j] == i:
resu[i] += 1
j +=1
i += 1
return resu

Minimum count to sort an array in Python by sending the element to the end

Here is the explanation of what I'm trying to say:-
Input:- 5 1 3 2 7
Output:- 3
Explanation:
In first move, we move 3 to the end. Our list becomes 5,1,2,7,3
In second move, we move 5 to the end. Our list becomes 1,2,7,3,5
In third move, we move 7 to the end. Our final list = 1,2,3,5,7
So, total moves are:- 3.
Here is what I tried to do, but failed.
a = [int(i) for i in input().split()]
count = 0
n = 0
while (n < len(a) - 1):
for i in range(0,n+1):
while (a[i] > a[i + 1]):
temp = a[i]
a.pop(i)
a.append(temp)
count += 1
n += 1
print(count, end='')
I'd like to request your assistance in helping in solving this question.
jdehesa's answer is basically right, but not optimal for cases, when there is more element of same value. Maybe more complex solution?
def min_moves(a):
c = 0
while(1):
tmp = None
for i in range(0, len(a)):
if a[i] != min(a[i:]) and (tmp is None or a[i] < a[tmp]):
tmp = i
if tmp is None:
return c
else:
a.append(a.pop(tmp))
c += 1
Edit:
Or if you don't need ordered list, there's much more easier solution just to count items that are out of order for the reason from jdehesa's solution :-D
def min_moves(a):
c = 0
for i in range(0, len(a)):
if a[i] != min(a[i:]):
c += 1
return c
Edit 2:
Or if you like jdehesa's answer more, small fix is to reduce lst to set, so it will get smallest index
sorted_index = {elem: i for i, elem in enumerate(sorted(set(lst)))}
I cannot comment yet.
I don't know if it can be done better, but I think the following algorithm gives the right answer:
def num_move_end_sort(lst):
# dict that maps each list element to its index in the sorted list
sorted_index = {elem: i for i, elem in enumerate(sorted(lst))}
moves = 0
for idx, elem in enumerate(lst):
if idx != sorted_index[elem] + moves:
moves += 1
return moves
print(num_move_end_sort([5, 1, 3, 2, 7]))
# 3
The idea is as follows. Each element of the list would have to be moved to the end at most once (it should be easy to see that a solution that moves the same element to the end more than once can be simplified). So each element in the list may or may not need to be moved once to the end. If an element does not need to be moved is because it ended up in the right position after all the moves. So, if an element is currently at position i and should end up in position j, then the element will not need to be moved if the number of previous elements that need to be moved, n, satisfies j == i + n (because, after those n moves, the element will indeed be at position j).
So in order to compute that, I sorted the list and took the indices of each element in the sorted list. Then you just count the number of elements that are not in the right position.
Note this algorithm does not tell you the actual sequence of steps you would need to take (the order in which the elements would have to be moved), only the count. The complexity is O(n·log(n)) (due to the sorting).
I think you can simplify your problem,
Counting elements that need to be pushed at the end is equivalent to counting the length of the elements that are not in sorted order.
l = [5, 1, 3, 2, 7]
sorted_l = sorted(l)
current_element = sorted_l[0]
current_index = 0
ans = 0
for element in l:
if current_element == element:
current_index += 1
if current_index < len(l):
current_element = sorted_l[current_index]
else:
ans += 1
print(ans)
Here the answer is 3

count inversions in mergesort python

I want to count how many inversions there are in a list while sorting the list using mergesort. This is my code so far where 'x' counts the ammount of inversions while the rest sorts it:
import sys
x = 0
def merge_sort(A):
merge_sort2(A, 0, len(A) - 1)
def merge_sort2(A, first, last):
if first < last:
middle = (first + last) // 2
merge_sort2(A, first, middle)
merge_sort2(A, middle + 1, last)
merge(A, first, middle, last)
def merge(A, first, middle, last):
global x
L = A[first:middle + 1]
R = A[middle + 1:last + 1]
L.append(sys.maxsize)
R.append(sys.maxsize)
i = j = 0
for k in range(first, last + 1):
if L[i] <= R[j]:
A[k] = L[i]
i += 1
else:
A[k] = R[j]
j += 1
x += 1
x += len(L[first + 1:])
When I call merge sort using a list, the variable x is support to give the amount of inversions in the list. So If the list was '[4,3,2,1], x would be 6. If the list was [1,2,3] x would be 0. I change the value of x whenever the right is greater than the left in the merge definition however, the number always gets way too big. What am I doing wrong?
Check my work but, I think instead of:
x += 1
x += len(L[first + 1:])
you want:
x += middle + 1 + j - k
basically, you want to add the difference between where item k is actually coming from, and where you'd expect it to come from if everything was already sorted.
Your merge step is a little hard for me to understand — I'm not sure why you are doing this (maybe just another way to merge?):
L.append(sys.maxsize)
R.append(sys.maxsize)
but I couldn't get everything to work out with the extra elements added to the partitions. And I think you end up counting the extra element in L as an inversion with each merge move from R
I think that's causing some of the problems. But you also have two other issues:
Your last line isn't quite the right logic:
x += len(L[first + 1:])
the number of inversions will the number of elements in L that you jump over. You're counting almost every element of L each time. Something like this works better:
x += len(L[i:])
and then at the end, you may have elements left over whose inversions you haven't counted yet. Maybe that's not an issue with your extra elements but in a more traditional merge it is. Here's the way I would count the inversions:
def merge(A, first, middle, last):
global x
L = A[first:middle+1]
R = A[middle+1:last+1]
i = j = 0
k = first
print(L, R)
while i<len(L) and j<len(R):
if L[i] <= R[j]:
A[k] = L[i]
i += 1
else:
A[k] = R[j]
j += 1
# count how many left in L
x += len(L[i:])
k += 1
# take care of any leftovers in L or R
while i < len(L):
A[k] = L[i]
i += 1
k+=1
while j < len(R):
A[k] = R[j]
j += 1
k+=1
x += len(L[i:])

Categories

Resources