Related
I have two lists of marks for the same set of students. For example:
A = [22, 2, 88, 3, 93, 84]
B = [66, 0, 6, 33, 99, 45]
If I accept only students above a threshold according to list A then I can look up their marks in list B. For example, if I only accept students with at least a mark of 80 from list A then their marks in list B are [6, 99, 45].
I would like to compute the smallest threshold for A which gives at least 90% of students in the derived set in B getting at least 50. In this example the threshold will have to be 93 which gives the list [99] for B.
Another example:
A = [3, 36, 66, 88, 99, 52, 55, 42, 10, 70]
B = [5, 30, 60, 80, 80, 60, 45, 45, 15, 60]
In this case we have to set the threshold to 66 which then gives 100% of [60, 80, 80, 60] getting at least 50.
This is an O(nlogn + m) approach (due to sorting) where n is the length of A and m is the length of B:
from operator import itemgetter
from itertools import accumulate
def find_threshold(lst_a, lst_b):
# find the order of the indices of lst_a according to the marks
indices, values = zip(*sorted(enumerate(lst_a), key=itemgetter(1)))
# find the cumulative sum of the elements of lst_b above 50 sorted by indices
cumulative = list(accumulate(int(lst_b[j] > 50) for j in indices))
for i, value in enumerate(values):
# find the index where the elements above 50 is greater than 90%
if cumulative[-1] - cumulative[i - 1] > 0.9 * (len(values) - i):
return value
return None
print(find_threshold([22, 2, 88, 3, 93, 84], [66, 0, 6, 33, 99, 45]))
print(find_threshold([3, 36, 66, 88, 99, 52, 55, 42, 10, 70], [5, 30, 60, 80, 80, 60, 45, 45, 15, 60]))
Output
93
66
First, define a function that will tell you if 90% of students in a set scored more than 50:
def setb_90pc_pass(b):
return sum(score >= 50 for score in b) >= len(b) * 0.9
Next, loop over scores in a in ascending order, setting each of them as the threshold. Filter out your lists according that threshold, and check if they fulfill your condition:
for threshold in sorted(A):
filtered_a, filtered_b = [], []
for ai, bi in zip(A, B):
if ai >= threshold:
filtered_a.append(ai)
filtered_b.append(bi)
if setb_90pc_pass(filtered_b):
break
print(threshold)
I want to get idexes of elemenent into 2d array by square shape
Some more info:
Let's pretend that i need get indexes of one element of 2d array
22 33 15
65 32 16
84 26 12
Index of '33' is 01
I want get all nearest elements of it, its: 22, 65, 32, 16, 15 and indexes is: 00, 10, 11, 12, 02
So, i want get indexes like that of any element of array
So x2, for 00 elemnts its 3 neighbor, for 01 its 5 and for 11 its 8 neighbors
And some more:
How can i handle out of index value?
Sorry for my bad english
Try this:
# example 2d arr
arr = [[22, 33, 15], [65, 32, 16], [84, 26, 12]]
# print
for row in arr:
for col in row:
print(col, end = " ")
print()
def getNeighbours(x, y, arr):
string = f'({x}, {y}): {arr[y][x]}'
neighbours = []
# get lengths for if check
col_length = len(arr)
row_length = len(arr[0])
# distance options for x, y; loop
for x_distance in [-1, 0, 1]:
for y_distance in [-1, 0, 1]:
# +0 and +0 == cur_position, so exclude
# new x/y < 0 would be out of bounds, so exclude
# new x/y == respective length would be out of bounds, so exclude
# all else ok, hence: 'if not'
if not ((x_distance == 0 and y_distance == 0) or \
(y+y_distance < 0 or y+y_distance == col_length) or \
(x+x_distance < 0 or x+x_distance == row_length)):
neighbours.append(arr[y+y_distance][x+x_distance])
return string, neighbours
# tests
result = getNeighbours(1, 0, arr)
print(result)
result = getNeighbours(1, 1, arr)
print(result)
result = getNeighbours(2, 1, arr)
print(result)
Output:
22 33 15
65 32 16
84 26 12
('(1, 0): 33', [22, 65, 32, 15, 16])
('(1, 1): 32', [22, 65, 84, 33, 26, 15, 16, 12])
('(2, 1): 16', [33, 32, 26, 15, 12])
Update: if speed is a concern, go with the numpy solution offered by Mechanic Pig.
To clarify the if logic a little bit, we could also have written something like this:
# distance options for x, y; loop
for x_distance in [-1, 0, 1]:
for y_distance in [-1, 0, 1]:
# x, y coordinates for a potential neighbour
new_x = x + x_distance
new_y = y + y_distance
if (x_distance == 0 and y_distance == 0):
# this will lead to the element itself, so ignore
continue
elif new_x < 0 or new_x == row_length:
# new_x should fall in range(row_length), so ignore
continue
elif new_y < 0 or new_y == col_length:
# same for y: new_y should fall in range(col_length), so ignore
continue
else:
# any other combination of ( new_x, new_y ) is OK; append element
neighbours.append(arr[new_y][new_x])
Since we simply want to continue after if and 2x elif, we could refactor this and say: if not (cond1 or cond2 or cond3): neighbours.append(), as above.
Consider using numpy.
import numpy as np
arr = np.array([[22, 33, 15], [65, 32, 16], [84, 26, 12]])
row, col = 0, 1
rows, cols = np.indices(arr.shape)
mask = np.maximum(np.abs(rows - row), np.abs(cols - col)) == 1
print(rows[mask], cols[mask])
# [0 0 1 1 1] [0 2 0 1 2]
print(arr[rows[mask], cols[mask]])
# [22 15 65 32 16]
I think you can master it with a little study. It's much faster than loop, and you don't need to consider the boundary problem.
I'm working on a time-series problem, and I have a list of events such that each data point represent several objects being pulled from an inventory.
Each time the value reaches below some threshold, I want to add a constant number to the inventory.
For example, I want:
(threshold = 55, constant = 20)
70 60 50 45 30 0 -5 -75
to become:
70 60 70 65 70 60 75 25
Is there a "pythonic" way (pandas, numpy, etc...) to do it with no loops?
Edit: the addition of constant can occur multiple times, and only effect the future (i.e indexes that are greater than the observed index). This is the code I'm using right now, and my goal is to lose the for loop:
threshold = 55
constant = 20
a = np.array([70, 60, 50, 45, 30, 0, -5, -75])
b = a.copy()
for i in range(len(b)):
if b[i] <= threshold:
temp_add_array = np.zeros(b.shape)
indexes_to_add = np.array(range(len(b))) >= i
temp_add_array[indexes_to_add] += constant
b += temp_add_array.astype(int)
print(b)
print('*************')
print('[70 60 70 65 70 60 75 25]')
Since you're allowing for numpy:
>>> import numpy as np
# threshold and constant
>>> t, c = 55, 20
>>> data = np.asarray([70, 60, 50, 45, 30, 0, -5, -75])
# if you allow for data == threshold
>>> np.where(data >= t, data, data + c*((t-1-data) // c + 1))
array([70, 60, 70, 65, 70, 60, 55, 65])
# if you enforce data > threshold
>>> np.where(data > t, data, data + c*((t-data) // c + 1))
array([70, 60, 70, 65, 70, 60, 75, 65])
But there is really no need for an external dependency for a task like that
# threshold and constant
>>> t, c = 55, 20
>>> data = [70, 60, 50, 45, 30, 0, -5, -75]
# if you allow for data == threshold
>>> [x if x >= t else x + c*((t-1-x)//c + 1) for x in data]
[70, 60, 70, 65, 70, 60, 55, 65]
# if you enforce data > threshold
>>> [x if x > t else x + c*((t-x)//c + 1) for x in data]
[70, 60, 70, 65, 70, 60, 75, 65]
Edit of OP
I doubt there's a (readable) solution for your problem without using a loop; best thing I could come up with:
>>> import numpy as np
>>> a = np.asarray([70, 60, 50, 45, 30, 0, -5, -75])
# I don't think you *can* get rid of the loop since there are forward dependencies in the the data
>>> def stock_inventory(data: np.ndarray, threshold: int, constant: int) -> np.ndarray:
... res = data.copy()
... for i, e in enumerate(res):
... if e <= threshold:
... res[i:] += constant
... return res
...
>>> stock_inventory(a, threshold=55, constant=20)
array([70, 60, 70, 65, 70, 60, 75, 25])
Assuming a numpy ndarray...
original array is named a
subtract the threshold value from a - name the result b
make a boolean array of b < 0 - name this array c
integer/floor divide b by -1 * constant - name this d (it could be named b as it is no longer needed)
add one to d - name this e
use c as a boolean index to add e to a for those values that were less than the threshold. a[c] += e[c]
There are three types of foods were provided i.e. meat, cake and pizza
and N different stores selling it where, i can only pick one type of food from
each store. Also I can only buy items in A, B and C numbers where 'A' means, Meat from total 'A' number of different stores (see example). My task is
to consume food, so that i can have maximum amount of energy.
example,
10 <= number of stores <br>
5 3 2 <= out of 10 stores I can pick meat from 5 stores only. Similarly,
I can pick cake from 3 out of 10 stores...
56 44 41 1 <= Energy level of meat, cake and pizza - (56, 44, 41) for first store.<br>
56 84 45 2
40 98 49 3
91 59 73 4
69 94 42 5
81 64 80 6
55 76 26 7
63 24 22 8
81 60 44 9
52 95 11 10
So to maximize my energy, I can consume...
Meat from store numbers:
[1, 4, 7, 8, 9] => [56, 91, 55, 63, 81]
Cake from store numbers:
[3, 5, 10] => [98, 94, 95]
Pizza from store numbers:
[2, 6] => [45, 80]
This leads me to eventually obtain a maximum energy level of 758.
As I am new to dynamic programming, I tried to solve it by generating unique combinations like,
10C5 * (10-5)C3 * (10-5-3)C2 = 2520
Here is my code,
nStores = 10
a, b, c = 5, 3, 2
matrix = [
[56,44,41],
[56,84,45],
[40,98,49],
[91,59,73],
[69,94,42],
[81,64,80],
[55,76,26],
[63,24,22],
[81,60,44],
[52,95,11]
]
count = a + b + c
data = []
allOverCount = [i for i in range(count)]
def genCombination(offset, depth, passedData, reductionLevel = 3):
if (depth == 0):
first = set(data)
if reductionLevel == 3:
return genCombination(0,b,[i for i in allOverCount if i not in first], reductionLevel=2)
elif reductionLevel == 2:
return genCombination(0,c,[i for i in allOverCount if i not in first], reductionLevel=1)
elif reductionLevel == 1:
xAns = 0
for i in range(len(data)):
if i < a:
xAns += matrix[data[i]][0]
elif i < a + b:
xAns += matrix[data[i]][1]
else:
xAns += matrix[data[i]][2]
return xAns
oneData = 0
for i in range(offset, len(passedData) - depth + 1 ):
data.append(passedData[i])
oneData = max(oneData, genCombination(i+1, depth-1, passedData, reductionLevel))
del data[-1]
return oneData
passedData = [i for i in range(count)]
finalOutput = genCombination(0,a,passedData)
print(finalOutput)
I know this is not the right way to do it. How can I optimize it?
This is a solution using Linear Programming through pulp (https://pypi.org/project/PuLP) that gives me the optimal solution
Maximum energy level: 758.0
Mapping of stores per foodtype: {1: [9, 2, 4], 0: [3, 8, 0, 6, 7], 2: [1, 5]}
The performance should be better than a hand-coded exhaustive solver I think.
from collections import defaultdict
import pulp
# data
nStores = 10
a, b, c = max_stores = 5, 3, 2
matrix = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
# create an LP problem
lp = pulp.LpProblem("maximize energy", sense=pulp.LpMaximize)
# create the list of indices for the variables
# the variables are binary variables for each combination of store and food_type
# the variable alpha[(store, food_typeà] = 1 if the food_type is taken from the store
index = {(store, food_type) for store in range(nStores) for food_type in range(3)}
alpha = pulp.LpVariable.dicts("alpha", index, lowBound=0, cat="Binary")
# add the constrain on max stores
for food_type, n_store_food_type in enumerate(max_stores):
lp += sum(alpha[(store, food_type)] for store in range(nStores)) <= n_store_food_type
# only one food type can be taken per store
for store in range(nStores):
lp += sum(alpha[(store, food_type)] for food_type in range(3)) <= 1
# add the objective to maximise
lp += sum(alpha[(store, food_type)] * matrix[store][food_type] for store, food_type in index)
# solve the problem
lp.solve()
# collect the results
stores_for_foodtype = defaultdict(list)
for (store, food_type) in index:
# check if the variable is active
if alpha[(store, food_type)].varValue:
stores_for_foodtype[food_type].append(store)
print(f"Maximum energy level: {lp.objective.value()}")
print(f"Mapping of stores per foodtype: {dict(stores_for_foodtype)}")
It looks like a modification to knapsack would solve it.
let's define our dp table as 4-dimensional array dp[N+1][A+1][B+1][C+1]
now some cell dp[n][a][b][c] means that we have considered n shops, out of them we picked a shops for meat,
b shops for cake and c shops for pizza and it stores max energy we can have.
Transitions are easy too, from some state dp[n][a][b][c] we can move to:
dp[n+1][a][b][c] if we skip n+1 th shop
dp[n+1][a+1][b][c] if we buy
meat from shop n+1
dp[n+1][a][b+1][c] if we buy cake from shop n+1
dp[n+1][a][b][c+1] if we buy pizza from shop n+1
All that's left is to fill dp table. Sample code:
N = 10
A,B,C = 5,3,2
energy = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
dp = {}
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
dp[n,a,b,c]=0
answer = 0;
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
#Case 1, skip n-th shop
if (n+1,a,b,c) in dp: dp[n+1,a,b,c] = max(dp[n+1,a,b,c], dp[n,a,b,c])
#Case 2, buy meat from n-th shop
if (n+1,a+1,b,c) in dp: dp[n+1,a+1,b,c] = max(dp[n+1,a+1,b,c], dp[n,a,b,c] + energy[n][0])
#Case 3, buy cake from n-th shop
if (n+1,a,b+1,c) in dp: dp[n+1,a,b+1,c] = max(dp[n+1,a,b+1,c], dp[n,a,b,c] + energy[n][1])
#Case 4, buy pizza from n-th shop
if (n+1,a,b,c+1) in dp: dp[n+1,a,b,c+1] = max(dp[n+1,a,b,c+1], dp[n,a,b,c] + energy[n][2])
answer = max(answer,dp[n,a,b,c])
print(answer)
I have 2 lists of numbers that represent points coordinates in a cartesian diagram.
My aim is to consider many points in a range of 10 as 1 point.
First example:
first point (1,2)
second point (2,3)
third point (3,4)
4th point (80,90)
Coordinates list:
#(1)
x = [1,2,3, 80]
Y = [2,3,4, 90 ]
I would like to delete the nearest point in a range of 10 (both in x and y), we could consider the first three numbers as a single one.
And result is:
x = [1, 80] and y = [2, 90] or
x = [2,80] and y = [3, 90] or
x = [3,80] and y = [4, 90]
If coordinates lists are:
#(2)
x = [1,2,3, 80]
Y = [2,3,70, 90 ]
we could consider the first 2 numbers as one
Result is:
x = [1, 80] and y = [2, 90] or
x = [2,80] and y = [3, 90] or
If they are:
#(3)
x = [1,2, 75, 78 , 80, 101]
Y = [2,3, 81, 86, 90 , 91]
Result:
x = [1,75, 101] and y = [2,81, 91] or
x = [1,78, 101] and y = [2,86, 91] or
x = [1,80, 101] and y = [2,90, 91] or
x = [2,75, 101] and y = [3,81, 91] or
x = [2,78, 101] and y = [3,86, 91] or
x = [2,80, 101] and y = [3,90, 91] or
I need only 1 of this 6 solutions. It's not important if I have x = [1,75] or x = [1,78].
The important thing is having close number as only one.
Last example:
x = [ 95, 154, 161, 135, 138, 116]
y = [158, 166, 168, 170, 170, 171]
In this case, only 3 points remain.
171 - 170 = 1 => 138 - 116 = 22 both results are in the range of 25 i choose to delete 116 and 171
170 - 170 = 0 => 138 - 135 = 3 both result are in the range of 25 i delete 170 and 138
170 - 168 = 2 => 135 - 161 = 26 i cannot delete
168 - 166 = 2 => 161 - 154 = 7 i delete 168 and 161
166 - 158 = 8 => 154 - 95 = 59 i cannot delete
x = [95, 154, 161, 135]
Y = [158, 166, 168, 170]
I repeat the operation and and I delete 161 in x and 168 in y because:
168 - 166 = 2 => 161 - 154 = 7
x = [95, 154, 135]
Y = [158, 166, 170]
y list is in ascending order.
What is the fastest way to compare them?
In general, it's easier to filter lists than to delete from them in-place.
But to filter easily, you need a single list, not two of them.
That's exactly what zip is for.
I'm not sure I understand exactly what you're asking for, because from the description it sounds like everything should stay except for 161 / 168. I'll show the rule it sounds like you were describing.
xy = zip(x, y)
new_xy = ((a, b) for a, b in xy if abs(a-b) <= 10)
x, y = zip(*new_xy)
Whatever your actual goal is, just replace the if abs(a-b) <= 10 with the right rule for "if this pair of values should be kept", and you're done.
To understand how this works, you should try printing out xy (or, if you're using Python 3.x, list(xy)), and the other intermediate bits.
(If you're using Python 2.x, and your list are very big, you should probably import itertools and then use xy = itertools.izip(x, y) to avoid creating an extra list for no good reason. If you're using Python 3.x, this isn't a problem, because zip doesn't create extra lists anymore.)
From further comments, it seems like maybe you want to check x[i] against x[i-1], not against y[i], and in fact you don't look at the y values at all—it's just that if x[i] goes, so does y[i].
To simplify things, let's take y out of the equation entirely, and just deal with filtering x. We can come back to the y later.
There are two ways to approach this. The first is to break down and build an explicit loop, where we keep track of a last_value each time through the loop. The second is to get a list of adjacent pairs within x.
The answer is, once again, zip:
x_pairs = zip(x, x[1:])
The only problem is that this doesn't give you anything to compare the first element to. For example:
>>> x = [95, 154, 161, 135, 138, 116]
>>> list(zip(x, x[1:]))
[(95, 154), (154, 161), (161, 135), (135, 138), (138, 116)]
That tells you whether or not to keep 154, 161, 135, 138, and 116… but what about that 95? Well, you never explained the rule for that. If you want to compare it to 0, do zip([0]+x, x). If you want to always keep it… you can just compare it to itself, so zip(x[:1]+x, x). And so on. Whatever rule you want is pretty easy to write. I'll go with the "compare to 0" rule.
So, now we've got these pairs of adjacent values (95, 95) then (95, 154), and so on. In each case, if the distance between two adjacent values is <= 10, we want to keep the latter value. That's easy:
x_pairs = zip([0]+x, x)
new_x = [pair[1] for pair in x_pairs if abs(pair[0]-pair[1]) <= 10]
Putting the y in there is the same trick we used originally: just zip it to the pairs, and zip it back out afterward. To make things a bit simpler, instead of zipping the pairs and then zipping y on, we'll just zip it all up at once:
x_pairs_y = zip([0]+x, x, y)
new_xy = (xxy[1:] for xxy in x_pairs_y if abs(xxy[0]-xxy[1]) <= 10)
new_x, new_y = zip(*new_xy)
In some of your explanation, it sounds like you want to compare adjacent x values, and also compare adjacent y values, and filter them out if either different is >10.
If so, that's just more of the same:
xy_pairs = zip([0]+x, [0]+y, x, y)
new_xy = (xyxy[2:] for xyxy in xy_pairs
if abs(xyxy[0]-xyxy[2]) <= 10 and abs(xyxy[1]-xyxy[3]) <= 10)
new_x, new_y = zip(*new_xy)
However, when things get so complicated that your simple one-liners don't fit on one line, you should consider factoring things out a bit. For example, instead of having a list of x values and a list of y values, why not create a Point class?
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
def long_diff(self, other):
return max(abs(self.x-other.x), abs(self.y-other.y))
points = (Point(x, y) for x, y in zip(x, y))
point_pairs = zip([Point(0, 0)]+points, points)
new_points = (pair[1] for pair in point_pairs if pair[0].long_diff(pair[1]) <= 10)
new_x, new_y = zip(*((point.x, point.y) for point in points))
It's a bit longer, but a lot easier to understand.
And it would be even easier to understand if you just used a list of Point objects in the first place, instead of separate lists of x and y values.
From further comments, it sounds like the condition you want is the exact opposite of the condition shown in my last two examples, and you don't know how to negate a condition.
First, not takes any expression and returns the opposite truth value. So:
new_xy = (xyxy[2:] for xyxy in xy_pairs
if not(abs(xyxy[0]-xyxy[2]) <= 10 and abs(xyxy[1]-xyxy[3]) <= 10))
Alternatively, "delete if the x distance is <= 10 and the y distance is <= 10" is the same as "keep if the x distance is > 10 or the y distance is > 10", right? So:
new_xy = (xyxy[2:] for xyxy in xy_pairs
if abs(xyxy[0]-xyxy[2]) > 10 or abs(xyxy[1]-xyxy[3]) > 10)
Also, if you're sure that your sequences are always monotonically increasing (that is, any element is always larger than the one before it), you don't really need the abs here (as long as you make sure to get the operand order right).
I was not sure why you "repeat the operation", or when to stop, so I have coded it up so the operation repeats until no more points are removed. Intermediate points are shown in order in a list as a two-element tuple of (x, y) coordinates rather than separate lists of x and y.
def outrange(pts, rnge):
partial = pts[::-1] # current points in reverse order
i, lastp = 0, []
while lastp != partial:
print('%i times around we have: %r' % (i, partial[::-1]))
i, lastp, partial = (i+1,
partial,
[(pn1x, pn1y)
for (pnx, pny), (pn1x, pn1y) in zip(partial[1:], partial)
if abs(pn1x - pnx) > rnge or abs(pn1y - pny) > rnge
] + partial[-1:])
return partial[::-1]
if __name__ == '__main__':
j = 0
for rnge, x, y in [(10, [1, 2, 3, 80] , [2, 3, 4, 90 ]),
(10, [1, 2, 3, 80] , [2, 3, 70, 90 ]),
(10, [1,2, 75, 78 , 80, 101], [2,3, 81, 86, 90 , 91]),
(25, [ 95, 154, 161, 135, 138, 116], [158, 166, 168, 170, 170, 171])]:
j += 1
print('\n## Example %i: Points outside range %s of:' % (j, rnge))
print(' x = %r\n y = %r' % (x, y))
pts = [(xx, yy) for xx, yy in zip(x,y)]
ans_x, ans_y = [list(z) for z in zip(*outrange(pts, rnge))]
print(' Answer: x = %r\n y = %r' % (ans_x, ans_y))
The output is:
## Example 1: Points outside range 10 of:
x = [1, 2, 3, 80]
y = [2, 3, 4, 90]
0 times around we have: [(1, 2), (2, 3), (3, 4), (80, 90)]
1 times around we have: [(1, 2), (80, 90)]
Answer: x = [1, 80]
y = [2, 90]
## Example 2: Points outside range 10 of:
x = [1, 2, 3, 80]
y = [2, 3, 70, 90]
0 times around we have: [(1, 2), (2, 3), (3, 70), (80, 90)]
1 times around we have: [(1, 2), (3, 70), (80, 90)]
Answer: x = [1, 3, 80]
y = [2, 70, 90]
## Example 3: Points outside range 10 of:
x = [1, 2, 75, 78, 80, 101]
y = [2, 3, 81, 86, 90, 91]
0 times around we have: [(1, 2), (2, 3), (75, 81), (78, 86), (80, 90), (101, 91)]
1 times around we have: [(1, 2), (75, 81), (101, 91)]
Answer: x = [1, 75, 101]
y = [2, 81, 91]
## Example 4: Points outside range 25 of:
x = [95, 154, 161, 135, 138, 116]
y = [158, 166, 168, 170, 170, 171]
0 times around we have: [(95, 158), (154, 166), (161, 168), (135, 170), (138, 170), (116, 171)]
1 times around we have: [(95, 158), (154, 166), (135, 170)]
2 times around we have: [(95, 158), (154, 166)]
Answer: x = [95, 154]
y = [158, 166]
The algorithm did what you did as noted in your explanation for example 4, but I questioned your logic in a comment to the main question as you say you drop a point then show it in the intermediate step.
If you calculated other results that are different to mine then please state why you get your differenc, i.e. what it is in your algorithm that I have not done, or look carefully at your answer for mistakes.