From a loop index k, obtain pairs i,j with i < j?

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-03 16:40:23

I think I got it (in Python):

def get_ij(n, k):
  j = k // (n - 1)  # // is integer (truncating) division
  i = k - j * (n - 1)
  if i >= j:
    i = (n - 2) - i
    j = (n - 1) - j
  return i, j

for n in range(2, 6):
  print n, sorted(get_ij(n, k) for k in range(n * (n - 1) / 2))

It basically folds the matrix so that it's (almost) rectangular. By "almost" I mean that there could be some unused entries on the far right of the bottom row.

The following pictures illustrate how the folding works for n=4:

and n=5:

Now, iterating over the rectangle is easy, as is mapping from folded coordinates back to coordinates in the original triangular matrix.

Pros: uses simple integer math.

Cons: returns the tuples in a weird order.

I think I found another way, that gives the pairs in lexicographic order. Note that here i > j instead of i < j.

Basically the algorithm consists of the two expressions:

i = floor((1 + sqrt(1 + 8*k))/2)
j = k - i*(i - 1)/2

that give i,j as functions of k. Here k is a zero-based index.

Pros: Gives the pairs in lexicographic order.

Cons: Relies on floating-point arithmetic.

Rationale:

We want to achieve the mapping in the following table:

k -> (i,j)
0 -> (1,0)
1 -> (2,0)
2 -> (2,1)
3 -> (3,0)
4 -> (3,1)
5 -> (3,2)
....

We start by considering the inverse mapping (i,j) -> k. It isn't hard to realize that:

k = i*(i-1)/2 + j

Since j < i, it follows that the value of k corresponding to all pairs (i,j) with fixed i satisfies:

i*(i-1)/2 <= k < i*(i+1)/2

Therefore, given k, i=f(k) returns the largest integer i such that i*(i-1)/2 <= k. After some algebra:

i = f(k) = floor((1 + sqrt(1 + 8*k))/2)

After we have found the value i, j is trivially given by

j = k - i*(i-1)/2

I'm not sure to understand exactly the question, but to sum up, if 0 <= i < n, 0 <= j < n , then you want to traverse 0 <= k < n*n

for (int k = 0; k < n*n; k++) {
    int i = k / n;
    int j = k % n;
    // ...
}

[edit] I just saw that i < j ; so, this solution is not optimal since there's less that n*n necessary iterations ...

גלעד ברקן

If we think of our solution in terms of a number triangle, where k is the sequence

1 
2  3 
4  5  6 
7  8  9  10
11 12 13 14 15
...   

Then j would be our (non zero-based) row number, that is, the greatest integer such that

j * (j - 1) / 2 < k

Solving for j:

j = ceiling ((sqrt (1 + 8 * k) - 1) / 2)

And i would be k's (zero-based) position in the row

i = k - j * (j - 1) / 2 - 1

The bounds for k are:

1 <= k <= n * (n - 1) / 2 

Is it important that you actually have two arithmetic functions f(k) and g(k) doing this? Because you could first create a list such as

L = []
for i in range(n-1):
    for j in range(n):
        if j>i:
            L.append((i,j))

This will give you all the pairs you asked for. Your variable k can now just run along the index of the list. For example, if we take n=5,

for x in L:
    print(x)

gives us

(0,1), (0,2), (0,3), (0,4), (1,2), (1,3), (1,4), (2,3), (2,4), (3,4)

Suppose your have 2<=k<5 for example, then

for k in range(2, 5)
    print L[k]

yields

(0,3), (0,4), (1,2)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!