Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slice a list based on an index and items behind it in Python

Tags:

python

list

Say I have an array of degree values, like this:

DEGREES = [     0, 15, 30, 45, 60,     75, 90, 105, 120,     135, 150, 165, 180,     195, 210, 225, 240,     255, 270, 285, 300,     315, 330, 345, ] 

I would pick an angle and then be able to bisect this hypothetical circle in order to make it easier to find the shortest route to the target direction.

Saying that, how can I pick a specific value, like 90, and then be able to find the previous 12 elements behind that, including the index wrapping around to the end?

So, taking that earlier value and applying to that list, I would get something like this:

[90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270] 

Using slice notation, I tried doing this:

index = DEGREES.index(90) print(DEGREES[index-12:index]) # start 12 values back, stop at index 

But this only prints an empty array.

Is there a way to slice a list so I can get the 12 previous values behind the index I'm using?

EDIT:

This turned out to be an XY Problem, my bad. Originally, I was trying to create a smooth rotation system in Pygame, with my attempts to calculate angles not working, I asked this question to solve a problem with yet another idea I was trying to implement. I ended up accepting the answer that helped me set up the smooth rotation system, but there are relevant answers to the original question below that.

like image 235
Mercury Platinum Avatar asked May 14 '19 17:05

Mercury Platinum


People also ask

How do you slice a list with indices?

To extract elements with specific indices from a Python list, use slicing list[start:stop:step] . If you cannot use slicing because there's no pattern in the indices you want to access, use the list comprehension statement [lst[i] for i in indices] , assuming your indices are stored in the variable indices .

What does [- 1 :] mean in Python?

Python also allows you to index from the end of the list using a negative number, where [-1] returns the last element. This is super-useful since it means you don't have to programmatically find out the length of the iterable in order to work with elements at the end of it.

How do you slice a list within a list Python?

With this operator, one can specify where to start the slicing, where to end, and specify the step. List slicing returns a new list from the existing list. If Lst is a list, then the above expression returns the portion of the list from index Initial to index End, at a step size IndexJump.

What is list indexing and slicing with an example?

What are Indexing and Slicing? Indexing: Indexing is used to obtain individual elements. Slicing: Slicing is used to obtain a sequence of elements. Indexing and Slicing can be be done in Python Sequences types like list, string, tuple, range objects.


2 Answers

Arithmetic with angles

Your goal isn't to slice, concatenate or reverse lists. Your goal is to do basic arithmetic with degrees and keep the results between 0 and 359. For this, you really should use the modulo operator %:

>>> 90 % 360 90 >>> 390 % 360 30 >>> -60 % 360 300 >>> 360 % 360 0 

Back to the question

If you only want to use this slicing for degrees with a constant increment, you could generate the desired list directly:

>>> STEP = 15 >>> list(range(0, 360, STEP)) [0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345] >>> def previous_degrees(start, n, step=STEP): ...     return [(start - i * step) % 360 for i in range(n + 1)] ...  >>> previous_degrees(90, 12) [90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270] >>> previous_degrees(90, 12, 30) [90, 60, 30, 0, 330, 300, 270, 240, 210, 180, 150, 120, 90] >>> previous_degrees(90, 6, 45) [90, 45, 0, 315, 270, 225, 180] 

Your real question

You wrote in a comment:

This array of degrees is designed to work with a smooth rotation system that I'm trying to create in pygame. Normally I would just find the difference between the current direction and the target direction and increment from there, but since the rotation rolls over at zero I have to hardcode the values to make sure that it will always go the shortest route possible.

From two angles, you need to determine if you should turn clockwise or anticlockwise. You can use modulo again to make sure that the rotation will be between -180° and 179°:

def shortest_rotation(start_angle, end_angle):     return (end_angle - start_angle + 180) % 360 - 180 

Here's an example:

>>> shortest_rotation(0, 90) 90 >>> shortest_rotation(90, 0) -90 >>> shortest_rotation(90, 90) 0 >>> shortest_rotation(90, 330) -120 >>> shortest_rotation(0, 180) -180 >>> shortest_rotation(0, 181) -179 >>> shortest_rotation(0, 179) 179 >>> shortest_rotation(10, 350) -20 

You can now create a list of angles, turning in the shortest direction:

def rotation_steps(start_angle, end_angle, n):     increment = shortest_rotation(start_angle, end_angle) / n     return [(start_angle + i * increment) % 360 for i in range(n + 1)] 

As an example:

>>> rotation_steps(90, 270, 12) [90.0, 75.0, 60.0, 45.0, 30.0, 15.0, 0.0, 345.0, 330.0, 315.0, 300.0, 285.0, 270.0] >>> rotation_steps(10, 350, 2) [10.0, 0.0, 350.0] 

The list uses float in order to avoid missing the end_angle if increment isn't an integer.

like image 50
Eric Duminil Avatar answered Oct 13 '22 18:10

Eric Duminil


Or you could use a deque:

from collections import deque from itertools import islice  dq = deque(reversed((0, 15, 30, 45, 60,     75, 90, 105, 120,     135, 150, 165, 180,     195, 210, 225, 240,     255, 270, 285, 300,     315, 330, 345)))  index = dq.index(90) dq.rotate(-index) res = list(islice(dq, 13)) # [90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270] 

You could use that as a function:

def f(i):     dq.rotate(-dq.index(i))     return list(islice(dq, 13))  #  f(90) = [90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270] 
like image 33
hiro protagonist Avatar answered Oct 13 '22 17:10

hiro protagonist