按绝对值和的顺序遍历对



我想按整数对的绝对值和的顺序进行迭代。该列表应该看起来像:

(0,0)
(-1,0)
(0,1)
(0,-1)
(1,0)
(-2,0)
(-1,1)
(-1,-1)
(0,2)
(0,-2)
(1,1)
(1,-1)
(2,0)
[...]

对于具有相同绝对值和的对,我不介意它们的顺序。

理想情况下,我希望能够永远创建成对,以便我可以依次使用每一个。你怎么能这么做?

对于一个固定的范围,我可以用一种难看的方式来创建对列表:

sorted([(x,y)for x in range(-20,21)for y in range(-20,21)if abs(x)+abs(y)<21],key=lambda x:sum(map(abs,x))

这不允许我永远迭代,它也不允许我一次得到一对。

这似乎奏效了:

from itertools import count  # Creates infinite iterator
def abs_value_pairs():
for absval in count():  # Generate all possible sums of absolute values
for a in range(-absval, absval + 1):  # Generate all possible first values
b = abs(a) - absval  # Compute matching second value (arbitrarily do negative first)
yield a, b
if b:  # If first b is zero, don't output again, otherwise, output positive b
yield a, -b

这将永远运行,并且有效地操作(避免不必要的重新计算)。

可以了。如果您真的希望它是无限的,请删除第一个if语句。

import itertools
def makepairs(count=3):
yield (0,0)
for base in itertools.count(1):
if base > count:  # optional escape
return        # optional escape
for i in range(base+1):
yield (i, base-i)
if base != i:
yield (i, i-base)
if i:
yield (-i, base-i)
if base != i:
yield (-i, i-base)
print(list(makepairs(9)))

下面的解生成一个包含任意长度元组的和流:

from itertools import count
def pairs(l = 2):
def groups(d, s, c = []):
if not d and sum(map(abs, c)) == s:
yield tuple(c)
elif d:
for i in [j for k in d[0] for j in {k, -1*k}]:
yield from groups(d[1:], s, c +[i])
for i in count():
yield from groups([range(i+1) for _ in range(l)], i)
p = pairs()
for _ in range(10):
print(next(p))

你可以创建一个无限生成器函数:

def pairSums(s = 0): # base generation on target sum to get pairs in order
while True:      # s parameter allows starting from a given sum
for i in range(s//2+1):                            # partitions
yield from {(i,s-i),(s-i,i),(i-s,-i),(-i,i-s)} # no duplicates
s += 1                                             # next target sum

输出:

for p in pairSums(): print(p)

(0, 0)
(0, 1)
(0, -1)
(1, 0)
(-1, 0)
(2, 0)
(-2, 0)
(0, -2)
(0, 2)
(1, 1)
(-1, -1)
(3, 0)
(0, 3)
(0, -3)
(-3, 0)
(1, 2)
(-1, -2)
(2, 1)
...

首先要注意的是,您可以在网格中显示非负值的总数:

x
3|3
2|23
1|123
0|0123
-+----
|0123y

这里我们可以看到一个模式,对角线是你的总数。我们来画一条系统的线。下面显示了您可以遍历它们的顺序:

x
3|6
2|37
1|148
0|0259
-+----
|0123y

这里矩阵包含迭代的顺序。

这解决了x和y的非负值的问题。为了得到剩下的,你可以只负x和y,确保当它们为0时你不这样做。像这样:

def generate_triplets(n):
yield 0, (0, 0)
for t in range(1, n + 1):  # Iterate over totals t
for x in range(0, t + 1):  # Iterate over component x
y = t - x  # Calclulate component y
yield t, (x, y)  # Default case is non-negative
if y > 0:
yield t, (x, -y)
if x > 0:
yield t, (-x, y)
if x > 0 and y > 0:
yield t, (-x, -y)
def generate_pairs(n):
yield from (pair for t, pair in generate_triplets(n))
# for pair in generate_pairs(10):
#     print(pair)
for t, (x, y) in generate_triplets(3):
print(f'{t} = abs({x}) + abs({y})')

这个输出

0 = abs(0) + abs(0)
1 = abs(0) + abs(1)
1 = abs(0) + abs(-1)
1 = abs(1) + abs(0)
1 = abs(-1) + abs(0)
2 = abs(0) + abs(2)
2 = abs(0) + abs(-2)
2 = abs(1) + abs(1)
2 = abs(1) + abs(-1)
2 = abs(-1) + abs(1)
2 = abs(-1) + abs(-1)
2 = abs(2) + abs(0)
2 = abs(-2) + abs(0)
3 = abs(0) + abs(3)
3 = abs(0) + abs(-3)
3 = abs(1) + abs(2)
3 = abs(1) + abs(-2)
3 = abs(-1) + abs(2)
3 = abs(-1) + abs(-2)
3 = abs(2) + abs(1)
3 = abs(2) + abs(-1)
3 = abs(-2) + abs(1)
3 = abs(-2) + abs(-1)
3 = abs(3) + abs(0)
3 = abs(-3) + abs(0)

或作为成对:

(0, 0)
(0, 1)
(0, -1)
(1, 0)
(-1, 0)
(0, 2)
(0, -2)
(1, 1)
(1, -1)
(-1, 1)
(-1, -1)
(2, 0)
(-2, 0)
...

对于每个和,在一个象限内走对角线,并将每个坐标旋转到其他象限:

from itertools import count
def coordinates():
yield 0, 0
for sum in count(1):
for x in range(sum):
y = sum - x
yield x, y
yield y, -x
yield -x, -y
yield -y, x

(我希望我理解了需求)我使用了itertools产品:

>>> for i in sorted(itertools.product(range(-5, 4), range(-5, 4)), key=lambda tup: abs(tup[0]) + abs(tup[1])):
print(i)
... 
(0, 0)
(-1, 0)
(0, -1)
(0, 1)
(1, 0)
(-2, 0)
(-1, -1)
(-1, 1)
(0, -2)
(0, 2)
(1, -1)
(1, 1)
(2, 0)
(-3, 0)
(-2, -1)
(-2, 1)
(-1, -2)
(-1, 2)
(0, -3)
(0, 3)
(1, -2)
(1, 2)
(2, -1)
...

最新更新