按照与中心单元的距离对单元进行排序

时间:2010-11-26 20:47:22

标签: python matrix optimization

我曾经有人问过我,那个时候似乎是一个无辜的问题:

我们如何按照与预定义/预先计算的中心单元的距离来排序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)]

我很惊讶我在那里获得了多少代码,因为这样一个微不足道的问题。

我的问题是:我可以更快和/或更短(使用更少的临时/函数调用)吗?

2 个答案:

答案 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)]

为了加快速度:

  • 不要采用平方根(如上面的代码所示):按距离的平方排序与按距离排序一样好,取平方根是相对慢不必要。
  • 利用8向对称:对一个八分圆进行排序并将其复制8次。

在评论中,PoorLuzer问道,“我也不明白你为什么要使用initx,centery = 2.5,2.5。”我希望这个数字能说清楚:

the centre of a 6x6 grid with coordinates running from 0 to 5 on each axis is at 2.5,2.5

由于我们都使用欧几里德距离公式,PoorLuzer也想知道我们的指标是如何不同的。好吧,我的度量标准是从每个正方形的中心到整个网格的中心的距离。例如,对于这8个单元,距中心的距离是√2.5=约1.58:

distance to centre for eight cells is sqrt(2.5)

而PoorLuzer将欧氏距离带到四个中心正方形中最近的一个(并将其四舍五入为整数)。对于相同的8个细胞,PoorLuzer指定距离为1:

distance for same eight cells is 1 in PoorLuzer's metric

答案 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)))