我有这个功能,用于检查在坐标系中行进时我们面临的方式,通过查看元组中的值如何增加,或者与路标列表中的下一个值相比减少。看一下这段代码,感觉很尴尬和笨拙:
a.facing = self.direction(a.travel_list[0], a.travel_list[1])
def direction(self, start, end):
s_width = start[0]
s_height = start[1]
e_width = end[0]
e_height = end[1]
# check directions
if s_height < e_height:
if s_width < e_width:
return 'right'
elif s_width > e_width:
return 'up'
else:
return 'up_right'
elif s_height > e_height:
if s_width < e_width:
return 'down'
elif s_width > e_width:
return 'left'
else:
return 'down_left'
elif s_height == e_height and s_width < e_width:
return 'down_right'
else:
return 'up_left'
将返回值调整为顺时针旋转一步。我的问题是,我们如何更改代码以使函数更短,更有效?
编辑:请注意,移动只能在指定的8个方向上进行。
答案 0 :(得分:4)
使用基于 cmp()返回值的字典:
def direction(self, start, end):
return table[cmp(start[0], end[0]), cmp(start[1], end[1])]
构建字典以总结您当前的逻辑:
table = {
(-1, -1): 'right',
(-1, 1): 'up',
(-1, 0): 'up_right',
...
}
如果您使用的是Python 3,则需要将自己的 cmp()函数定义为:
cmp = lambda x, y: -1 if x < y else 1 if x > y else 0
答案 1 :(得分:2)
在稍微更改您的功能时,您可以使用简单的功能定义返回路线列表:
def direction(self, start, end):
delta = (end[0] - start[0], end[1] - start[1])
s = []
if delta[1]>0 : s.append("up")
elif delta[1]<0 : s.append("down")
if delta[0]>0 : s.append("right")
elif delta[0]<0 : s.append("left")
return s
这里将包含0,1或2个成员,具体取决于旅行方向。如果没有移动,列表将为空。
如果您特别需要指定格式的返回值,则只需从列表中提取值并根据需要进行解析。
我不完全理解您对顺时针移位的需求,但如果那不可更改,那么我建议最初使用一些较短/较简单的值作为占位符,然后使用字典来处理占位符与所需文本的替换以及顺时针移位。
答案 2 :(得分:1)
第1步:获取y和x距离
第2步:调用atan2(x,y)获取角度(http://docs.python.org/2/library/math.html#math.atan2)
步骤3:除以pi / 4并舍入到最接近的整数,得到-4到4之间的值
步骤4:现在你可以做一个case / switch,每个值都是不同的基本方向(-4和4将是相同的方向,例如都是东方)
编辑:我刚刚意识到这只有在您考虑时才有用东比东还高10度。 XD让我想一个更好的......
编辑2:好的,试试这个:
第1步:制作两个值的元组
步骤2:值1 = cmp(x1,x2)
步骤3:值2 = cmp(y1,y2)
步骤4:在元组表中查找方向(例如0,1是北,0,-1是南,1,1是东北,依此类推)并返回结果
答案 3 :(得分:0)
您可以使用and
运营商:
a.facing = self.direction(a.travel_list[0], a.travel_list[1])
def direction(self, start, end):
s_width, s_height, e_width, e_height = start[0], start[1], end[0], end[1]
# multiple assignments
# check directions
if s_height < e_height and s_width < e_width:
return 'right'
elif s_height < e_height and s_width > e_width:
return 'up'
elif s_height < e_height: # this will get executed if the top two are false
return 'up_right' # its similar to using the `else` in a nested conditional
elif s_height > e_height and s_width < e_width:
return 'down'
elif s_height > e_height and s_width > e_width:
return 'left'
elif s_height > e_height:
return 'down_left'
elif s_height == e_height and s_width < e_width:
return 'down_right'
else:
return 'up_left'
答案 4 :(得分:0)
如果您的原始代码是正确的,那么您的映射有些我不明白。假设开始是(宽度,高度),正如你所说的那样,或者(x,y)正如我在下面使用的那样,假设x向右增加而y增加(数学中的通常情况,但你的要求似乎是有点不同),这里有一个简洁的方法来告诉结束相对于开始的位置(使用你的字符串名称集):
DIR_STR_LIST = ("up", "down", "right", "left")
def direction3((sx, sy), (ex, ey)):
conds = (sy < ey, ey < sy, sx < ex, ex < sx)
istr = DIR_STR_LIST.__iter__()
return '_'.join([istr.next() for c in conds if c or not istr.next()])
当or not istr.next()
为false时,需要c
来推进迭代器。
虽然 简洁,但它比我想要的更加丑陋。我认为可能比原始代码表现更好(因为列表推导快),但这是简单性能更好的情况。原始代码快5倍(哎哟!)。