我想列举一些整数因子的所有可能产品,只能达到某个最大值:
P((2, 3, 11), 10)
会返回(2, 3, 4, 6, 8, 9)
。P((5, 7, 13), 30)
会返回(5, 7, 13, 25)
。这似乎是树遍历,一旦达到最大值,树枝就会停止生长,但我不知道树枝数量的界限是什么。这个问题推荐使用什么算法或习惯用法?到目前为止我最接近的是itertools.product()
,它似乎为每个输出集设置了固定数量的术语(例如2)。
对于上下文,我试图检查n的互质数字。在这种情况下,n本身是上限,因子列表是n的因子。我试着将这个问题概括一点。
答案 0 :(得分:3)
我喜欢这种方法,它包括将输入列表中的所有元素乘以1,然后将所有结果乘以输入列表中的元素等,直到达到限制。
def signature_seq(signature, limit):
products = set((1,))
for factor in signature:
new_products = set()
for prod in products:
x = factor * prod
while x <= limit:
new_products.add(x)
x *= factor
products.update(new_products)
products.remove(1)
return products
这应该做你想要的:
>>> print(sorted(signature_seq((2, 3, 11), 10)))
[2, 3, 4, 6, 8, 9]
>>> print(sorted(signature_seq((5, 7, 13), 30)))
[5, 7, 13, 25]
顺便说一下,如果给出一个以2开头的连续素数列表,那么这是一个smooth number生成器。
答案 1 :(得分:2)
这是使用生成器(和itertools.count
)的解决方案:
from itertools import count
def products(numbers, limit):
numbers = set(numbers) # needs a set to pop from, not a tuple
while numbers:
n = numbers.pop()
for r in (n ** e for e in count(1)):
if r > limit:
break
yield r
for p in products(numbers, limit / r):
yield r * p
因为它是一个生成器,它返回一个迭代器 - 并且结果没有排序,所以对于你想要的特定输出,你可以这样称呼它:
>>> sorted(products((2, 3, 11), 10))
[2, 3, 4, 6, 8, 9]
>>> sorted(products((5, 7, 13), 30))
[5, 7, 13, 25]
答案 2 :(得分:0)
仅使用带有元组(2,3,4)的itertools
的想法:
拥有多种笛卡儿产品:
(2,),(3,),(4,) # repeat 1
(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4) # repeat 2
...
对于每个元组,使用reduce
和operator.mul
以及起始值1,将它们相乘:
reduce(operator.mul, tuple, 1)
这将产生2级笛卡尔积的乘法:
[reduce(operator.mul,t,3) for t in itertools.product((1,2,3),repeat=2)]
>>>[3, 6, 9, 6, 12, 18, 9, 18, 27]
现在,我们需要增加repeat
直到满足停止条件,例如:每次乘法都会产生大于top
的结果。由于最重要的samllest值是2
(因为1
次1
很多次只是1因此它不会计数)我们可以乘以2倍x而低于top
。因此:top/2 = x
表示我们可以遍历range(1,top/2)
:
[reduce(operator.mul,t,1) for c in range(1,10/2) for t in itertools.product((1,2,3),repeat=2) if reduce(operator.mul, t, 1) < 10]
这会产生重复的值,所以我们将它们转换成一组:
set([reduce(operator.mul,t,1) for c in range(1,10/2) for t in itertools.product((1,2,3),repeat=2) if reduce(operator.mul, t, 1) < 10])
仅使用itertools
可能会很麻烦,但解决方案看起来很漂亮。我确信它可以通过引入更好的停止条件来优化。最终代码如下所示:
注意:有一个素数定理,可以让您将停止条件优化为math.sqrt(top)
import math
def f(t,m):
return set([reduce(operator.mul, t1, 1) for c in range(1,int(math.sqrt(m)) for t1 in itertools.product(t,repeat=c) if reduce(operator.mul,t1,1) < m])
f((2,3,4),10)
>>>set([2, 3, 4, 6, 8, 9])
希望这可能会给你另一个想法:)