I need to traverse all pairs i,j
with 0 <= i < n
, 0 <= j < n
and i < j
for some positive integer n
.
Problem is that I can only loop through another variable, say k
. I can control the bounds of k
. So the problem is to determine two arithmetic methods, f(k)
and g(k)
such that i=f(k)
and j=g(k)
traverse all admissible pairs as k
traverses its consecutive values.
How can I do this in a simple way?
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)
来源:https://stackoverflow.com/questions/26129044/from-a-loop-index-k-obtain-pairs-i-j-with-i-j