我在python中表示一个带有2D列表的网格。我想在列表中选择一个点(x,y)并确定它的位置......右边缘,左上角,中间的某个位置......
目前我正在检查:
# left column, not a corner
if x == 0 and y != 0 and y != self.dim_y - 1:
pass
# right column, not a corner
elif x == self.dim_x - 1 and y != 0 and y != self.dim_y - 1:
pass
# top row, not a corner
elif y == 0 and x != 0 and x != self.dim_x - 1:
pass
# bottom row, not a corner
elif y == self.dim_y - 1 and x != 0 and x != self.dim_x - 1:
pass
# top left corner
elif x == 0 and y == 0:
pass
# top right corner
elif x == self.dim_x - 1 and y == 0:
pass
# bottom left corner
elif x == 0 and y == self.dim_y - 1:
pass
# bottom right corner
elif x == self.dim_x - 1 and y == self.dim_y - 1:
pass
# somewhere in middle; not an edge
else:
pass
在确定位置后我有一些功能做某事
dim_x和dim_y是列表的维度。
如果没有那么多if-else语句,有没有更好的方法呢?有效的东西会很好,因为这部分逻辑被称为几百万次...它是模拟退火。
提前致谢。另外,什么是更好的措辞标题呢?
答案 0 :(得分:7)
def location(x,y,dim_x,dim_y):
index = 1*(y==0) + 2*(y==dim_y-1) + 3*(x==0) + 6*(x==dim_x-1)
return ["interior","top","bottom","left","top-left",
"bottom-left","right","top-right","bottom-right"][index]
答案 1 :(得分:3)
# initially:
method_list = [
bottom_left, bottom, bottom_right,
left, middle, right,
top_left, top, top_right,
]
# each time:
keyx = 0 if not x else (2 if x == self.dim_x - 1 else 1)
keyy = 0 if not y else (2 if y == self.dim_y - 1 else 1)
key = keyy * 3 + keyx
method_list[key](self, x, y, other_args)
未经测试......但总的想法应该透过。
在目标职位大幅度重新定位之后更新“有效的东西会很好,因为这部分逻辑被称为几百万次......这是模拟退火”:
最初你不喜欢测试链,并说你正在调用一个函数来处理8个案例中的每一个。如果你想快速(在Python中):保留测试链,并且内联处理每个案例而不是调用函数。
你能用psyco吗?另外,请考虑使用Cython。
答案 2 :(得分:1)
如果我理解正确,你有一个生成在网格中的坐标(x,y)的集合,并且你想知道,给定任何坐标,无论它是在网格内还是在边缘上。
我将采取的方法是在进行比较之前对网格进行规范化,使其原点为(0,0),右上角为(1,1),然后我只需要知道用于确定其位置的坐标。让我解释一下。
0)设_max表示最大值和_min,例如,x_min是坐标x的最小值; let _new代表标准化值。
1) Given (x,y), compute: x_new = (x_max-x)/(x_max-x_min) and y_new=(y_max-y)/(y_max-y_min).
2) [this is pseudo code]
switch y_new:
case y_new==0: pos_y='bottom'
case y_new==1: pos_y='top'
otherwise: pos_y='%2.2f \% on y', 100*y_new
switch x_new:
case x_new==0: pos_x='left'
case x_new==1: pos_x='right'
otherwise: pos_x='%2.2f \% on x', 100*x_new
print pos_y, pos_x
It would print stuff like "bottom left" or "top right" or "32.58% on y 15.43% on x"
Hope that helps.
答案 3 :(得分:0)
我想如果你真的想以完全不同的方式对待所有这些案例,你的解决方案是可以的,因为它非常明确。紧凑的解决方案可能看起来更优雅,但可能更难维护。这实际上取决于if-blocks中发生的事情。
只要对角落进行共同处理,人们可能更愿意用一个聪明的if语句来抓住这些案例。
答案 4 :(得分:0)
这样的东西可能更具可读性/可维护性。它可能比嵌套的if语句快得多,因为它只测试每个条件一次并通过一个很好而快速的字典发送。
class LocationThing:
def __init__(self, x, y):
self.dim_x = x
self.dim_y = y
def interior(self):
print "interior"
def left(self):
print "left"
def right(self):
print "right"
def top(self):
print "top"
def bottom(self):
print "bottom"
def top_left(self):
print "top_left"
def top_right(self):
print "top_right"
def bottom_left(self):
print "bottom_left"
def bottom_right(self):
print "bottom_right"
location_map = {
# (left, right, top, bottom)
( False, False, False, False ) : interior,
( True, False, False, False ) : left,
( False, True, False, False ) : right,
( False, False, True, False ) : top,
( False, False, False, True ) : bottom,
( True, False, True, False ) : top_left,
( False, True, True, False ) : top_right,
( True, False, False, True ) : bottom_left,
( False, True, False, True ) : bottom_right,
}
def location(self, x,y):
method = self.location_map[(x==0, x==self.dim_x-1, y==0, y==self.dim_y-1)]
return method(self)
l = LocationThing(10,10)
l.location(0,0)
l.location(0,1)
l.location(1,1)
l.location(9,9)
l.location(9,1)
l.location(1,9)
l.location(0,9)
l.location(9,0)
当您运行上述内容时,它会打印
top_left
left
interior
bottom_right
right
bottom
bottom_left
top_right
答案 5 :(得分:0)
对于一个快速的内循环函数,你可以咬住子弹并执行丑陋的:使用重复的术语嵌套if else语句,这样每次比较只进行一次,并且运行速度快两倍< / strong>作为一个更清洁的答案(通过mobrule):
import timeit
def f0(x, y, x_dim, y_dim):
if x!=0:
if x!=x_dim: # in the x interior
if y!=0:
if y!=y_dim: # y interior
return "interior"
else: # y==y_dim edge 'top'
return "interior-top"
else:
return "interior-bottom"
else: # x = x_dim, "right"
if y!=0:
if y!=y_dim: #
return "right-interior"
else: # y==y_dim edge 'top'
return "right-top"
else:
return "right-bottom"
else: # x=0 'left'
if y!=0:
if y!=y_dim: # y interior
return "left-interior"
else: # y==y_dim edge 'top'
return "left-top"
else:
return "left-bottom"
r_list = ["interior","top","bottom","left","top-left",
"bottom-left","right","top-right","bottom-right"]
def f1(x,y,dim_x,dim_y):
index = 1*(y==0) + 2*(y==dim_y-1) + 3*(x==0) + 6*(x==dim_x-1)
return r_list[index]
for x, y, x_dim, y_dim in [(4, 4, 5, 6), (0, 0, 5, 6)]:
t = timeit.Timer("f0(x, y, x_dim, y_dim)", "from __main__ import f0, f1, x, y, x_dim, y_dim, r_list")
print "f0", t.timeit(number=1000000)
t = timeit.Timer("f1(x, y, x_dim, y_dim)", "from __main__ import f0, f1, x, y, x_dim, y_dim, r_list")
print "f1", t.timeit(number=1000000)
给出了:
f0 0.729887008667 # nested if-else for interior point (no "else"s)
f1 1.4765329361
f0 0.622623920441 # nested if-else for left-bottom (all "else"s)
f1 1.49259114265
所以它比mobrule的答案要快两倍,这是我发布的最快的代码。 (此外,我将mobrule的字符串列表移出功能,因为结果加快了50%。)速度超过美丽?
如果您想要一个简洁易读的解决方案,我建议:
def f1(x, y, x_dim, y_dim):
d_x = {0:"left", x_dim:"right"}
d_y = {0:"bottom", y_dim:"top"}
return d_x.get(x, "interior")+"-"+d_y.get(y, "interior")
和我的时间一样快。