说我有一个度值数组,像这样:
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,
]
Run Code Online (Sandbox Code Playgroud)
我会选择一个角度,然后能够将这个假设圆二等分,以便更轻松地找到到达目标方向的最短路径。
这样说,我如何选择一个特定的值(例如)90
,然后能够找到该值后面的前12个元素,包括结束时环绕的索引?
因此,采用该更早的值并将其应用于该列表,我将得到如下信息:
[90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270]
Run Code Online (Sandbox Code Playgroud)
使用切片符号,我尝试这样做:
index = DEGREES.index(90)
print(DEGREES[index-12:index]) # start 12 values back, stop at index
Run Code Online (Sandbox Code Playgroud)
但这只会打印一个空数组。
有没有办法对列表进行切片,这样我就可以得到所使用索引后面的12个先前值?
编辑:
原来这是一个XY问题,我不好。最初,我试图在Pygame中创建一个平滑的旋转系统,但尝试计算角度不起作用,我问了这个问题以解决另一个我尝试实现的想法的问题。我最终接受了有助于建立平滑旋转系统的答案,但是下面的原始问题有相关答案。
Eri*_*nil 39
您的目标不是切片,连接或反向列表。您的目标是对度进行基本算术运算,并将结果保持在0
和之间359
。为此,您确实应该使用模运算符%
:
>>> 90 % 360
90
>>> 390 % 360
30
>>> -60 % 360
300
>>> 360 % 360
0
Run Code Online (Sandbox Code Playgroud)
如果只想将此切片用于具有恒定增量的度,则可以直接生成所需的列表:
>>> 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]
Run Code Online (Sandbox Code Playgroud)
您在评论中写道:
这个度数数组旨在与我试图在pygame中创建的平滑旋转系统一起使用。通常,我只是会发现当前方向和目标方向之间的差异,然后从那里开始递增,但是由于旋转翻转为零,因此我必须对这些值进行硬编码,以确保始终能走到最短的路径。
从两个角度,您需要确定应该顺时针还是逆时针旋转。您可以再次使用模数以确保旋转范围在-180°和179°之间:
def shortest_rotation(start_angle, end_angle):
return (end_angle - start_angle + 180) % 360 - 180
Run Code Online (Sandbox Code Playgroud)
这是一个例子:
>>> 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
Run Code Online (Sandbox Code Playgroud)
现在,您可以创建一个角度列表,以最短的方向转动:
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)]
Run Code Online (Sandbox Code Playgroud)
举个例子:
>>> 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]
Run Code Online (Sandbox Code Playgroud)
该列表使用float以避免丢失end_angle
if increment
不是整数。
hir*_*ist 18
或者您可以使用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]
Run Code Online (Sandbox Code Playgroud)
您可以将其用作函数:
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]
Run Code Online (Sandbox Code Playgroud)
Joh*_*ado 11
这样的事情可能更直接:
index = DEGREES.index(90)
print([DEGREES[i] for i in range(index, index-13, -1)])
Run Code Online (Sandbox Code Playgroud)
在这些情况下,派上用场的NumPy函数是np.roll
,顾名思义,该函数滚动数组中的元素,也如文档中所述:
超出最后位置的元素将在第一个位置重新引入
这正是我们需要的,以便将列表中的第一项从后面滚动到90
出现的索引。
因此,一种方法可能是90
使用通过index
list方法出现的索引,然后将数组移至给定索引的-k
位置k
。然后,我们可以对列表进行切片,并将其最后一个n
元素取反:
import numpy as np
l = [
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 roll_n_reversed(l, i, n):
return np.roll(l, -l.index(i)-1)[:-(n+1):-1]
roll_n_reversed(l, 90, 13)
Run Code Online (Sandbox Code Playgroud)
产生预期的输出:
array([ 90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270])
Run Code Online (Sandbox Code Playgroud)
基于itertools
(cycle
和islice
)的解决方案:
from itertools import cycle, islice
DEGREES = cycle(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)))
next(item for item in DEGREES if item == 90) # advance to next 90
res = [90] + list(islice(DEGREES, 12))
# [90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270]
Run Code Online (Sandbox Code Playgroud)
您可以将其打包成一个单行函数:
def f(i):
return [next(d for d in DEGREES if d == i), *islice(DEGREES, 12)]
# f(90) = [90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270]
Run Code Online (Sandbox Code Playgroud)
甚至使用dropwhile
(如评论中所述):
from itertools import cycle, islice, dropwhile
def f(i):
return list(islice(dropwhile(lambda d: d != i, DEGREES), 13))
Run Code Online (Sandbox Code Playgroud)
如果您的列表与上面打印的完全一样,您还可以使用range
以下命令动态生成切片:
def f(i, d=15, n=13):
return [deg % 360 for deg in range(i, i-n*d, -d)]
# f(90) = [90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270]
Run Code Online (Sandbox Code Playgroud)