如何缩短这个if语句?

时间:2013-01-24 03:56:43

标签: python if-statement

我有这个功能,用于检查在坐标系中行进时我们面临的方式,通过查看元组中的值如何增加,或者与路标列表中的下一个值相比减少。看一下这段代码,感觉很尴尬和笨拙:

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个方向上进行。

5 个答案:

答案 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倍(哎哟!)。