我曾经有人问过我,那个时候似乎是一个无辜的问题:
我们如何按照与预定义/预先计算的中心单元的距离来排序2D阵列中的单元格。
这是一个表格,显示特定单元格与预定义中心单元格的距离(它们的值为0)。值n表示距离中心的n个单元格:
+----+----+----+----+----+----+----+----+
| 4 | 4 | 3 | 3 | 3 | 3 | 4 | 4 |
+----+----+----+----+----+----+----+----+
| 4 | 3 | 2 | 2 | 2 | 2 | 3 | 4 |
+----+----+----+----+----+----+----+----+
| 3 | 2 | 1 | 1 | 1 | 1 | 2 | 3 |
+----+----+----+----+----+----+----+----+
| 3 | 2 | 1 | 0 | 0 | 1 | 2 | 3 |
+----+----+----+----+----+----+----+----+
| 3 | 2 | 1 | 0 | 0 | 1 | 2 | 3 |
+----+----+----+----+----+----+----+----+
| 3 | 2 | 1 | 1 | 1 | 1 | 2 | 3 |
+----+----+----+----+----+----+----+----+
| 4 | 3 | 2 | 2 | 2 | 2 | 3 | 4 |
+----+----+----+----+----+----+----+----+
| 4 | 4 | 3 | 3 | 3 | 3 | 4 | 4 |
+----+----+----+----+----+----+----+----+
我通过计算欧几里德空间中(x1,y1)和(x2,y2)之间的直线距离并使用旧学校的“装饰 - 排序 - 未装饰”方法对它们进行排序来解决问题。
这就是我最终的结果:
import math
boardMaxRow = 8
boardMaxCol = 8
thatAbsurdLargeValue = ( 1 + boardMaxRow + boardMaxCol )
centerCells = ( ( 3, 3 ), ( 3, 4 ), ( 4, 3 ), ( 4, 4 ) )
cellsOrderedFromTheCenter = {}
for row in xrange( boardMaxRow ):
for col in xrange( boardMaxCol ):
minDistanceFromCenter = thatAbsurdLargeValue
for ( centerX, centerY ) in centerCells:
# straight line distance between ( x1, y1 ) and ( x2, y2 ) in an Euclidean space
distanceFromCenter = int( 0.5 + math.sqrt( ( row - centerX ) ** 2 + ( col - centerY ) ** 2 ) )
minDistanceFromCenter = min( minDistanceFromCenter, distanceFromCenter )
cellsOrderedFromTheCenter[ ( row, col ) ] = minDistanceFromCenter
board = [ keyValue for keyValue in cellsOrderedFromTheCenter.items() ]
import operator
# sort the board in ascending order of distance from the center
board.sort( key = operator.itemgetter( 1 ) )
boardWithCellsOrderedFromTheCenter = [ key for ( key , Value ) in board ]
print boardWithCellsOrderedFromTheCenter
输出:
[(3, 3), (4, 4), (4, 3), (3, 4), (5, 4), (2, 5), (2, 2), (5, 3), (3, 2), (4, 5), (5, 5), (2, 3), (4, 2), (3, 5), (5, 2), (2, 4), (1, 3), (6, 4), (5, 6), (2, 6), (5, 1), (1, 2), (6, 3), (1, 5), (3, 6), (4, 1), (1, 4), (2, 1), (6, 5), (4, 6), (3, 1), (6, 2), (7, 3), (4, 7), (3, 0), (1, 6), (3, 7), (0, 3), (7, 2), (4, 0), (2, 0), (5, 7), (1, 1), (2, 7), (6, 6), (5, 0), (0, 4), (7, 5), (6, 1), (0, 2), (7, 4), (0, 5), (0, 7), (6, 7), (7, 6), (7, 7), (0, 0), (7, 1), (6, 0), (1, 0), (0, 1), (7, 0), (0, 6), (1, 7)]
我很惊讶我在那里获得了多少代码,因为这样一个微不足道的问题。
我的问题是:我可以更快和/或更短(使用更少的临时/函数调用)吗?
答案 0 :(得分:1)
要缩短(并使用稍微不同的指标):
>>> rows, cols, centerx, centery = 6, 6, 2.5, 2.5
>>> [p[1:] for p in sorted((((x - centerx) ** 2 + (y - centery) ** 2, x, y)
... for x in xrange(rows) for y in xrange(cols)))]
[(2, 2), (2, 3), (3, 2), (3, 3), (1, 2), (1, 3),
(2, 1), (2, 4), (3, 1), (3, 4), (4, 2), (4, 3),
(1, 1), (1, 4), (4, 1), (4, 4), (0, 2), (0, 3),
(2, 0), (2, 5), (3, 0), (3, 5), (5, 2), (5, 3),
(0, 1), (0, 4), (1, 0), (1, 5), (4, 0), (4, 5),
(5, 1), (5, 4), (0, 0), (0, 5), (5, 0), (5, 5)]
为了加快速度:
在评论中,PoorLuzer问道,“我也不明白你为什么要使用initx,centery = 2.5,2.5。”我希望这个数字能说清楚:
由于我们都使用欧几里德距离公式,PoorLuzer也想知道我们的指标是如何不同的。好吧,我的度量标准是从每个正方形的中心到整个网格的中心的距离。例如,对于这8个单元,距中心的距离是√2.5=约1.58:
而PoorLuzer将欧氏距离带到四个中心正方形中最近的一个(并将其四舍五入为整数)。对于相同的8个细胞,PoorLuzer指定距离为1:
答案 1 :(得分:1)
更短很容易:
coordinates = [(x,y) for y in range(boardMaxRow)
for x in range(boardMaxCol)]
def dist(A,B):
a,b = A
c,d = B
# real euklidian distance without rounding
return (a-c)**2+(b-d)**2
print list(sorted(coordinates,
key=lambda x: min(dist(x,c) for c in centerCells)))