对角线(锯齿形)导线的坐标索引

时间:2018-11-22 23:54:13

标签: python matrix

所以我有一个像这样的4x4矩阵

 |0 1 2 3
-+-------
0|0 1 3 6
1|2 4 7 a
2|5 8 b d
3|9 c e f

,并且我按其中的十六进制字符指定的顺序遍历它。所以从(0,0)开始,然后从(1,0),(0,1),(2,0),(1,1),(0,2)...

下面是代码:

def diagonal(n):
    for a in range(n):
        for b in range(a + 1):
            yield a - b, b
    for a in range(n - 1):
        for b in range(n - a - 1):
            yield n - b - 1, b + 1 + a

重复给出

for x, y in diagonal(4):
    print((x, y))

# (0, 0)
# (1, 0)
# (0, 1)
# (2, 0)
# (1, 1)
# (0, 2)
# (3, 0)
# (2, 1)
# (1, 2)
# (0, 3)
# (3, 1)
# (2, 2)
# (1, 3)
# (3, 2)
# (2, 3)
# (3, 3)

这完全符合我的预期。我所停留的部分试图在我给它赋予索引的位置上创建一个函数,并为其提供坐标。因此,对于我的4x4矩阵,(仍然是十六进制)

0 -> (0, 0)
1 -> (1, 0)
2 -> (0, 1)
3 -> (2, 0)
4 -> (1, 1)
5 -> (0, 2)
6 -> (3, 0)
7 -> (2, 1)
8 -> (1, 2)
9 -> (0, 3)
a -> (3, 1)
b -> (2, 2)
c -> (1, 3)
d -> (3, 2)
e -> (2, 3)
f -> (3, 3)

我打算继续使用可变大小的平方矩阵,所以我不能仅仅将这些值硬编码为字典。

我已经花了好几个小时试图使它起作用,但是我一生都无法使它起作用。

这不是家庭作业,只是我在业余时间正在做的事情,它正在慢慢把我推向高潮。

如果不清楚,请随时询问。

先谢谢了。

编辑: 我想有人会对这篇文章Traverse Matrix in Diagonal strips发表评论,这很相似,但是和我的第一个函数一样,它只迭代坐标,而我无法从索引中得出坐标。

2 个答案:

答案 0 :(得分:4)

这是一个似乎可以执行您想要的功能的函数。代码后有解释。

from math import sqrt

def triangular(n):
    return n * (n + 1) // 2

def coords_from_index(ndx, n=4):
    if ndx < triangular(n):
        basecol = (int(sqrt(8 * ndx + 1)) - 1) // 2
        row = ndx - triangular(basecol)
        col = basecol - row
    else:
        oldcol, oldrow = coords_from_index(n**2 - 1 - ndx, n)
        row = n - 1 - oldrow
        col = n - 1 - oldcol
    return col, row

# Test code
n = 4
for ndx in range(n**2):
    print(hex(ndx)[2:], '->', coords_from_index(ndx, n))

该测试代码的打印输出为:

0 -> (0, 0)
1 -> (1, 0)
2 -> (0, 1)
3 -> (2, 0)
4 -> (1, 1)
5 -> (0, 2)
6 -> (3, 0)
7 -> (2, 1)
8 -> (1, 2)
9 -> (0, 3)
a -> (3, 1)
b -> (2, 2)
c -> (1, 3)
d -> (3, 2)
e -> (2, 3)
f -> (3, 3)

这是我的代码的简要说明。

就像您的代码按顺序生成坐标一样,我将正方形的左上三角形与右下三角形区别对待。首先让我们看一下左上角的三角形,对于大小为4的正方形,它包括索引09

如果查看每列的顶部数字,则会看到它们是“三角数”,即从0开始的连续整数之和。因此,第一行是00+10+1+20+1+2+3。这些数字的众所周知的公式是

triangular(n) = n * (n + 1) // 2

所以我为此写了一个小例程。如果您知道三角数(称为ndx)并想找到n,则可以使用代数来求解二次方程,然后得到

n = (sqrt(8 * ndx + 1) - 1) // 2

如果将sqrt替换为int(sqrt(,则得到相同的三角数结果,并且还获得介于两个三角数之间的任何ndx的“基数” 。然后,您可以使用索引和“基数”来找到索引的相应列和行。

现在,如果查看右下角的三角形,其中包括索引af,则可以看到与左上角三角形对称。我选择使用这种对称性来计算任何这些索引的行和列。我本可以更直接地计算它们,但是我使用的方法效果很好。

请注意,如果您使用非常大的nndx值,由于浮点算法的变数,int(sqrt(并不总是给出正确的答案。但是在发生这种情况之前,ndx必须真的大,大约为2**50。让我知道您是否需要一个更可靠的例程来计算整数平方根。

答案 1 :(得分:3)

这基本上是一个算法问题:)

我建议使用以下算法:

  1. 查找所请求索引所依赖的对角线
  2. 找到该对角线上的索引位置
  3. 推断坐标

我建议的实现如下:

首先,准备每个对角线中第一个线性索引的数组。
例如在4x4矩阵中,数组将如下所示:[0, 1, 3, 6, 10, 30, 15]
通知这些基本上是垃圾箱。这意味着在第i个对角线中找到所有维护a[i] <= index < a[i+1]的线性索引。

比,当收到索引时:

  1. 查找找到所请求索引的对角线。
    您可以通过找到满足bin[d] <= index < bin[d]

  2. d
  3. 找到该对角线上的位置。
    这是bin [d]与索引之间的距离。这意味着如果 index-bin [d] = k ,则索引位于该对角线上的第k个位置。

  4. 推断坐标。
    到目前为止,您已经发现索引位于第d个对角线上的第k个位置。

    让我们表示矩阵的大小为 MxM
    如果x <= M-1比对角线(k,d-k)
    如果x> M-1比我们在对角线上(d-(m-1)+ k,(m-1)-k)
    当我们插入之前找到的k时,我们将找到所需的坐标。

实施

def ind2cor(index):
    d = bisect_left(a, index)
    if index != a[d]:
        d -= 1

    k = index - a[d]

    if d <= m-1:
        return k, d - k
    else:
        return d - (m - 1) + k, (m - 1) - k

示例:

m = 4
a = [0, 3, 6, 10, 13, 15]
for i in range(16):
    print('{}: {}'.format(i, ind2cor(i)))

收益:

0: (0, 0)
1: (0, 1)
2: (1, 0)
3: (0, 2)
4: (1, 1)
5: (2, 0)
6: (0, 3)
7: (1, 2)
8: (2, 1)
9: (3, 0)
10: (1, 3)
11: (2, 2)
12: (3, 1)
13: (2, 3)
14: (3, 2)
15: (3, 3)

我还可以提供一种生成对角线索引的方法:

def genereate_diagonal_indices(m):
    a = [0]
    for i in range(1, m):
        a.append(a[-1] + i)
    for i in range(m, 1, -1):
        a.append(a[-1] + i)
     return a

因此您可以在上面的代码中使用a = genereate_diagonal_indices(m)