i need to iterate over a tuple of indices. all indices must be in the range
[0, N) with the condition i > j. The toy example I present here deals with
only two indices; I will need to extend that to three (with i > j > k) or more.
The basic version is this:
N = 5
for i in range(N):
for j in range(i):
print(i, j)
and it works just fine; the output is
1 0
2 0
2 1
3 0
3 1
3 2
4 0
4 1
4 2
4 3
I don't want to have one more indentation level for every additional index,
therefore I prefer this version:
for i, j in ((i, j) for i in range(N) for j in range(i)):
print(i, j)
this works perfectly well, does what it should and gets rid of the extra
indentation level.
I was hoping to be able to have something more elegant (for two indices that is
not all that relevant, but for three or more it becomes more relevant). What I came up with so far is this:
from itertools import combinations
for j, i in combinations(range(N), 2):
print(i, j)
This iterates over the same pair of indices just fine. The only thing that is
different is the order in which the pairs appear:
1 0
2 0
3 0
4 0
2 1
3 1
4 1
3 2
4 2
4 3
As the order of what I am doing with these indices is relevant, I therefore cannot use this.
Is there an elegant, short, pythonic way to iterate over these indices in the same order that the very first example produces? Keep in mind that N will be large, so sorting is not something I would want to do.
解决方案
You could solve this generally as follows:
def indices(N, length=1):
"""Generate [length]-tuples of indices.
Each tuple t = (i, j, ..., [x]) satisfies the conditions
len(t) == length, 0 <= i < N and i > j > ... > [x].
Arguments:
N (int): The limit of the first index in each tuple.
length (int, optional): The length of each tuple (defaults to 1).
Yields:
tuple: The next tuple of indices.
"""
if length == 1:
for x in range(N):
yield (x,)
else:
for x in range(1, N):
for t in indices(x, length - 1):
yield (x,) + t
In use:
>>> list(indices(5, 2))
[(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3)]
>>> list(indices(5, 3))
[(2, 1, 0), (3, 1, 0), (3, 2, 0), (3, 2, 1), (4, 1, 0), (4, 2, 0), (4, 2, 1), (4, 3, 0), (4, 3, 1), (4, 3, 2)]