I having trouble with insertion sort and I feel I might be missing the point of the sort and misunderstanding the fundamentals.
We were given a insertion sort which edited the array which was fed into it. We are tasked with then modifying the code we have been given to then create a constructive insertion sort which will not edit the original array
This is the code I have so far
def append(A, x):
return A + [x]
def insertionSort(A):
B = []
B = append(B, A[0])
for i in range(1, len(A)):
B = insert(B, A[i], i, A)
return str(B)
def insert(B, k, hi, A):
print(B, k, hi)
for x in range(hi-1, -1, -1):
if B[x] <= k:
B = append(B, k)
return B
B = append(B, A[x])
B[0] = k
return B
print(insertionSort([2,4,6,8,10,1,3,5,7,9]))
However after the third or forth element in the list it begins adding all the items to the end of the list in reverse order
[2] 4 1
[2, 4] 6 2
[2, 4, 6] 8 3
[2, 4, 6, 8] 10 4
[2, 4, 6, 8, 10] 1 5
[1, 4, 6, 8, 10, 10, 8, 6, 4, 2] 3 6
[1, 4, 6, 8, 10, 10, 8, 6, 4, 2, 1, 10, 8, 6, 4, 3] 5 7
[1, 4, 6, 8, 10, 10, 8, 6, 4, 2, 1, 10, 8, 6, 4, 3, 3, 1, 10, 8, 6, 5] 7 8
[1, 4, 6, 8, 10, 10, 8, 6, 4, 2, 1, 10, 8, 6, 4, 3, 3, 1, 10, 8, 6, 5, 7] 9 9
[1, 4, 6, 8, 10, 10, 8, 6, 4, 2, 1, 10, 8, 6, 4, 3, 3, 1, 10, 8, 6, 5, 7, 9]
I cannot wrap my head around why this is wrong.
Thanks dearly to anyone who can help.
The reverse problem is at the foor loop in the insert function
when your loop hit those values it starts the reverse mode
def insert(B, k, hi, A):
# when hi=5
for x in range(hi-1, -1, -1):
# x = 4
# here B[4] is 10 and k=1 so B[4] <= 1 is False
# you program does not execute the inside of if
# instead it jumps to B = append(B, A[x]) where A[4] == 10
# and the this loop goes in reverse mode from 4 to 0
# when x = 3
# B[x] = 8 so 8 is not less or equal of k where k = 1
# so it jumps again to B = append(B, A[x]) where A[x] = A[3] = 8
# so it append 8
# and so on
# when this loop is finished your list will look like [1,4,6,8,10,10,8,6,4,2]
# the 1 gets added when the loop is finished at B[0] = k
# and then rest of the outputs are result of the loop inside the insertionSort func
if B[x] <= k:
B = append(B, k)
return B
B = append(B, A[x])
B[0] = k
return B
Here is a solution:
def insertionSort(A):
copy_sort = A.copy()
for i in range(1, len(copy_sort)):
item = copy_sort[i]
j = i - 1
while j >= 0 and copy_sort[j] > item:
copy_sort[j + 1] = copy_sort[j]
j -= 1
copy_sort[j + 1] = item
return copy_sort
your_array = [2,4,6,8,10,1,3,5,7,9]
sorted = insertionSort(your_array)
print(your_array)
print(sorted)
You need to work out your algorithm on paper, and then translate those steps to Python code. What you've implemented is convoluted and incorrect.
Most of all, insert is very confused as to the information it needs and how it should do its job. As best I can see from your code, you want this routine to insert a given value k into the appropriate location in list B. For some reason, you've also passed in list A and the value's location in that list, neither of which is applicable.
What your routine does then is strange; starting from the end of B (using i instead of B itself), the code checks the elements of B; every time it finds a value in the list less than the new one, it appends the new one to the end of B. Regardless of that comparison, it appends the corresponding element of A to B.
Nowhere do you insert the element in the proper place.
Rewrite this code. Start with the minimum necessary information:
def insert(arr, new_val):
# insert new_val into the list arr
Now, your function has two steps to carry out:
Find the proper position for new_val
Make a new list with the value inserted into that spot.
You return that new list.
Can you move on from there?
Related
Details:
Given an array numbers = {2, 7, 8, 5, 1, 6, 3, 9, 4}. Check the below conditions, both the conditions should be satisfied.
If arr[i – 1] < arr[i] > arr[i + 1], where 1 < i < N – 1, then arr[i] is the peak element.
If arr[0] > arr[1], then arr[0] is the peak element, where N is the size of the array.
If arr[N – 2] < arr[N – 1], then arr[N – 1] is the peak element, where N is the size of the array.
If more than one peak element exists in the array, then the minimum value among them needs to be printed.
Example:
1st Iteration - 8, 6, 9 are peak values.
Remove the smallest ele. Remove 6.
New arr {2, 7, 8, 5, 1, 3, 9, 4}. Output Arr - {6}
2nd Iteration - 8, 9 are peak values.
Remove the smallest ele. Remove 8.
New arr {2, 7, 5, 1, 3, 9, 4}. Output Arr - {6, 8}
3rd Iteration - 7, 9 are peak values.
Remove the smallest ele. Remove 7.
New arr {2, 5, 1, 3, 9, 4}. Output Arr - {6, 7, 8}
4th Iteration - 5, 9 are peak values.
Remove the smallest ele. Remove 5.
New arr {2, 1, 3, 9, 4}. Output Arr - {6, 7, 8, 5}
5th Iteration - 2, 9 are peak values.
Remove the smallest ele. Remove 2.
New arr {1, 3, 9, 4}. Output Arr - {6, 7, 8, 5, 2}
6th Iteration - 9 are peak values.
Remove the smallest ele. Remove 9.
New arr {1, 3, 4}. Output Arr - {6, 7, 8, 5, 2, 9}
7th Iteration - 4 are peak values.
Remove the smallest ele. Remove 4.
New arr {1, 3}. Output Arr - {6, 7, 8, 5, 2, 9, 4}
8th Iteration - 3 are peak values.
Remove the smallest ele. Remove 3.
New arr {1}. Output Arr - {6, 7, 8, 5, 2, 9, 4, 3}
9th Iteration - 1 are peak values.
Remove the smallest ele. Remove 1.
New arr {1}. Output Arr - {6, 7, 8, 5, 2, 9, 4, 3, 1}
Output: {6, 8, 7, 5, 2, 9, 4, 3, 1}
My Code:
nums = [2, 7, 8, 5, 1, 6, 3, 9, 4]
def deleteMinimalPeaks(nums):
from queue import PriorityQueue as pq
if len(nums) <= 1:
return nums
peakq = pq()
out = []
n = len(nums)
ridx = [i+1 for i in range(n)]
lidx = [i-1 for i in range(n)]
nums.append(-1)
if nums[0] > nums[1]:
peakq.put((nums[0], 0))
if nums[n-1] > nums[n-2]:
peakq.put((nums[n-1], n-1))
for i in range(1, n-1):
if nums[i] > nums[i-1] and nums[i] > nums[i+1]:
peakq.put((nums[i], i))
if peakq.empty():
nums.pop()
return nums[::-1]
while(not peakq.empty()):
val, idx = peakq.get()
out.append(val)
if len(out) == len(nums):
break
if ridx[idx] <= n-1:
lidx[ridx[idx]] = lidx[idx]
if lidx[idx] >= 0:
ridx[lidx[idx]] = ridx[idx]
if ridx[idx] <= n-1 \
and nums[ridx[idx]] > nums[ridx[ridx[idx]]] \
and nums[ridx[idx]] > nums[lidx[ridx[idx]]]:
peakq.put( (nums[ridx[idx]], ridx[idx]) )
if lidx[idx] >= 0 \
and nums[lidx[idx]] > nums[lidx[lidx[idx]]] \
and nums[lidx[idx]] > nums[ridx[lidx[idx]]]:
peakq.put( (nums[lidx[idx]], lidx[idx]) )
return out
deleteMinimalPeaks(nums)
Question:
The code is giving the correct result.
However, is there a more pythonic way to write the innermost while loop?
I would probably use itertools to help navigate the results. Using the recipe for triplewise with some slight adaptations, we can easily iterate over multiple values in the list.
The adaptation we will make is adding buffer to the start and end of the data. This will allow us to detect if we're on the edge of the data or not.
from itertools import pairwise
def triplewise(iterable):
for (a, _), (b, c) in pairwise(pairwise([None, *iterable, None])):
yield a, b, c
nums = [2, 7, 8, 5, 1, 6, 3, 9, 4]
for a, b, c in triplewise(nums):
print(a, b, c)
None 2 7
2 7 8
...
3 9 4
9 4 None
To create a method which returns just the peaks, all you have to do is examine the middle number against its edges. We know values of None are edges.
def find_peeks(iterable):
for a, b, c in triplewise(iterable):
if (a is None or b > a) and (c is None or b > c):
yield b
nums = [2, 7, 8, 5, 1, 6, 3, 9, 4]
print(list(find_peeks(nums)))
[8, 6, 9]
To make this iterative, you could have the find_peeks method also return the index of the peek. Then you can use min to find the minimum element to remove and continue:
def find_peeks(iterable):
for i, (a, b, c) in enumerate(triplewise(iterable)):
if (a is None or b > a) and (c is None or b > c):
yield b, i
def iterative_peeks(iterable):
while iterable:
peek, index = min(find_peeks(iterable))
yield peek
del iterable[index]
nums = [2, 7, 8, 5, 1, 6, 3, 9, 4]
print(list(iterative_peeks(nums)))
[6, 8, 7, 5, 2, 9, 4, 3, 1]
Shift the items in the given array, by some number of times, as shown in the below examples;
array = [1, 2 ,3 , 4, 5, 6]
k1 = 2
k2 = -3
k3 = 20
test1:
cirShift(array, k1)
Result: [5, 6, 1, 2, 3, 4]
test2:
cirShift(array, k2)
Result: [4, 5, 6, 1, 2, 3]
test3:
cirShift(array, k3)
Result: [5, 6, 1, 2, 3, 4]
I have used the below to achieve the right-rotate a list by k positions;
def rightRotateByOne(A):
Fin= A[-1]
for i in reversed(range(len(A) - 1)):
A[i + 1] = A[i]
A[0] = Fin
def rightRotate(A, k):
if k < 0 or k >= len(A):
return
for i in range(k):
rightRotateByOne(A)
if __name__ == '__main__':
A = [1, 2, 3, 4, 5, 6, 7]
k = 3
rightRotate(A, k)
print(A)
As of now, able to obtain results for test1 but would like to achieve the test2 and test3
Even easier, split the array in half given the boundary, swap and glue back:
def cirShift(a, shift):
if not shift or not a:
return a
return a[-shift%len(a):] + a[:-shift%len(a)]
Courtesy of #KellyBundy, a short-circut one-liner:
def cirShift(a, shift):
return a and a[-shift%len(a):] + a[:-shift%len(a)]
I think this question may be an exercise in self learning ('how to do X using just python'), so my answer is auxiliary, but you can always use np.roll():
#test 1
import numpy as np
a = [1, 2 ,3, 4, 5, 6]
np.roll(a, 2)
gives output
[5, 6, 1, 2, 3, 4]
and
#test 2
np.roll(a, -2)
gives output
[3, 4, 5, 6, 1, 2]
Even if you give a number that is larger than the array size, it handles the overflow:
#test 3
np.roll(a, 10)
gives output
[3, 4, 5, 6, 1, 2]
Rolling also works in multiple dimension arrays and across specified axes, which is pretty neat.
def shift(l, shift_t):
r = [*l]
for n in range(abs(shift_t)):
if shift_t < 0:
r = r[1:] + [r[0]]
else:
r = [r[-1]] + r[:-1]
return r
The key is to take one item of the list and place it on the opposite side, which is essentially all that shifting is doing. If you shift negative, you put the first one at the end, and if you shift positive, you put the last one at the beginning.
So I have a list li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] and I only want to print out elements that are a part of an arithmetic sequence 6n - 5 (1st, 7th and 13th).
How can I do that if I have a list with n elements?
You could simply say
print([x for x in li if x % 6 == 1])
or, alternatively, if you just want the sequence and don't want to bother about creating li in the first place,
print([6*n-5 for n in range(1, (13+5)//6+1)])
Use the code:
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
new=[]
for i in li:
if int((i+5)/6)==((i+5)/6):
#You can also use
#if ((i+5)/6).is_integer():
new.append(i)
I tried to make it as easy as possible.
Hope it helps :)
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
for n in range(1,len(li)+1): #choose n such that it is length of the list since it cant have more values than the number of values in the list.
for i in li:
if (6*n - 5) == i:
print(i)
Hope this helps
Thanks
Michael
From what I understand, you want the elements whose positions are generated by the sequence. Hence, you want elements from an array of length n whose index is from the sequence function 6x-5.
NOTE: I am assuming you are using 1-based indexing, which means, when you say 1st element in your list, you intend to get 1 and not 2.
n = 13
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
# generate the sequence till n
seq = []
x = 1
while 6*x-5 <= n:
seq.append(6*x-5)
x += 1
# Print the elements from the sequence:
for idx in seq:
print(li[idx-1])
# If you want to store it in another list:
li2 = [li[idx-1] for idx in seq]
Below is a more generic and efficient way for above code:
n = 13
li = list(range(1, n+1)) # More easy to write
# More efficient way is to create a generator function
def get_seq(n):
x = 1
while 6*x-5 <= n:
yield 6*x-5
x += 1
# Get the generator object
seq = get_seq(n)
# Print the elements from the sequence:
for idx in seq:
print(li[idx-1])
# Want to store it in another list:
seq = get_seq(n) # Don't forget to get a new generator object.
li2 = [li[idx-1] for idx in seq]
Output for both snippets:
1
7
13
Hope the answer helps, and remove confusion for others as well ;)
You can simply generate the sequence for any n.
for example:
n = 10
print([ 6*x - 5 for x in range(1,n)])
output:
[1, 7, 13, 19, 25, 31, 37, 43, 49]
>>> [Finished in 0.2s]
But if you just want to filter your existing list li:
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
print([ x for x in li if x % 6 == 1 ])
output:
[1, 7, 13]
>>>
[Finished in 0.3s]
li[1] is 2, li[7] is 8 and the element with the index 13 is out of range.
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
for num, i in enumerate(li):
if ((num + 5)/6).is_integer():
print(i)
# 2
# 8
If you want to start with the index 1 add start=1 to the enumerate() function.
for num, i in enumerate(li, start=1):
if ((num + 5)/6).is_integer():
print(i)
# 1
# 7
# 13
Say I had a list:
lis = [4, 8, 2, 4, 6]
And I want to go through each value in the list and double it but If I come across the number 2, after I double it I should skip the next number and only double the on after. For example, in the end my list should look like this.
lis = [8, 16, 4, 4, 12]
Can this be possible with a for loop?
The algorithm boils down what number you are using to double the items in the list (1 or 2). Here is my take on this problem:
lis = [4, 8, 2, 4, 6]
def double_with_my_condition(l, doubler=2):
for i in l:
yield i * doubler
if i == 2:
doubler = 1
continue
doubler = 2
new_lis = [*double_with_my_condition(lis)]
print(new_lis)
Outputs:
[8, 16, 4, 4, 12]
I wrote out a really simple solution that should be easy to understand since it appears you are a beginner
lis = [4, 8, 2, 4, 6]
new_lis = []
i = 0
while (i < len(lis)):
new_lis.append(lis[i] * 2)
if (lis[i] == 2):
if (i+1 < len(lis)):
new_lis.append(lis[i+1])
i = i+1
i = i+1
print(new_lis)
This creates a new list, loops through the old list, appends the doubled value to the new list, skips a number if the value at the index is 2.
This will work!
Method-1:
lis = [4, 8, 2, 4, 6]
for i in range(len(lis)-1, -1, -1):
if(lis[i-1] == 2):
continue
else:
lis[i] = lis[i]*2
lis
Method-2:
lis1 = [4, 8, 2, 4, 6]
indices = [i+1 for i, x in enumerate(lis1) if x == 2] #Storing indices of next to 2
lis2 = [i*2 for i in lis1]
for i in indices:
lis2[i] = lis1[i] # replacing the previous values
print(lis2)
You can also use list comprehensions
lis = [4, 8, 2, 4, 6]
print([lis[x] if lis[x - 1] == 2 else lis[x] * 2 for x in range(len(lis))])
I need to make make an android pattern or just a pattern in a 3x3 matrix. The pattern is [8, 7, 6, 5, 4, 3, 2, 0, 1] and I need to plot it in a 3x3 matrix. The first entry in the pattern is the beginning point and it connects to the second in the row. The result needs to be the following:
8, 9, 7
6, 5, 4
3, 2, 1
pattern = [8, 7, 6, 5, 4, 3, 2, 0, 1]
matrix = [0,0,0,0,0,0,0,0,0]
lst = ([matrix[i:i + 3] for i in range(0, len(matrix), 3)])
for i in lst:
print(i)
for char in pattern:
matrix[char]=char
Do you mean something like this:
def print_pattern(pattern, cols=3):
for ii, pp in enumerate(pattern):
if ii % cols == 0:
print("")
print(pp),
Then you can call this function as
pattern = [8, 7, 6, 5, 4, 3, 2, 0, 1]
print_pattern(pattern)
This results in the following output:
8 7 6
5 4 3
2 0 1
If you want to print the pattern in the opposite order you can pass a reversed list of your pattern, e.g.:
print_pattern(reversed(pattern))
Gives the following output:
1 0 2
3 4 5
6 7 8
This functions accepts an integer n and an iterable. It makes a list of tuples of width n from that iterable
def mat(n, it):
return list(zip(*[iter(it)]*n))