【问题标题】:Iterating through primes a certain way以某种方式遍历素数
【发布时间】:2012-04-17 20:01:01
【问题描述】:

目前我正在输出列表中的所有素数组合以及该子集的乘积,如下所示:

from operator import mul
from itertools import combinations

primes = [2, 3, 5, 7, 11]

for r in range(1,len(primes)):
    for combo in combinations(primes,r+1):
        print combo, reduce(mul, combo)

哪些输出

(2,) 2
(3,) 3
(5,) 5
(7,) 7
(11,) 11
(2, 3) 6
(2, 5) 10
(2, 7) 14
(2, 11) 22
(3, 5) 15
(3, 7) 21
(3, 11) 33
(5, 7) 35
(5, 11) 55
(7, 11) 77
(2, 3, 5) 30
(2, 3, 7) 42
(2, 3, 11) 66
(2, 5, 7) 70
(2, 5, 11) 110
(2, 7, 11) 154
(3, 5, 7) 105
(3, 5, 11) 165
(3, 7, 11) 231
(5, 7, 11) 385
(2, 3, 5, 7) 210
(2, 3, 5, 11) 330
(2, 3, 7, 11) 462
(2, 5, 7, 11) 770
(3, 5, 7, 11) 1155
(2, 3, 5, 7, 11) 2310

现在假设我们正在查看以下块:

(2, 5, 7) 70
(2, 5, 11) 110
(2, 7, 11) 154
(3, 5, 7) 105
(3, 5, 11) 165
(3, 7, 11) 231
(5, 7, 11) 385
(2, 3, 5, 7) 210
(2, 3, 5, 11) 330

为了举例,我想遍历乘积

问题是,如果我此时 break,它会认为我正在尝试破坏所有长度为 3 的元组并移动到 (2,3,5,7),从而跳过乘积 继续,我最终会遍历大量元组,我知道这将是浪费时间。如果我知道 (2, 5, 11) 太大,那么 (2, 7, 11) 显然也太大了,我不应该评估它。

我不确定我的问题是否清楚,但是否有另一种方法可以生成输出顺序更符合我的结构的组合?

【问题讨论】:

  • 如果你想在任意时间前进,你必须手动生成连击。
  • 这就是我害怕的,哈哈
  • 这是欧拉计划的问题之一吗? (只是出于好奇。)

标签: python combinations itertools


【解决方案1】:

“问题”是combinations 生成器以特定顺序发出所有长度为r 的元组。您希望它们以不同的顺序出现。因此,您需要编写自己的combinations 生成器。

这些类型的生成器通常是递归编写的:要从 i 发出所有 r-length 组合,您首先删除一个元素 - 第一个元素 - 然后递归地从其余部分发出所有 (r-1)-length 组合.

现在,您想要做的是停止产品太大时立即递归,这样您就不会发出不必要的元组。不幸的是,编写此类生成器的通常方式不允许您这样做,因为字典顺序与“按乘积递增的顺序”不同。

这意味着您必须找到一种不同的递归方式,每次都会增加数字的乘积。稍加思考,您就会想到以下算法:

  • 从尽可能小的元组开始。
  • 对于元组的每个索引,尝试将其“向上提升”到下一个素数。仅在以下情况下执行此操作
    • 产品仍然低于限制,并且
    • 元组保持排序顺序。
  • 这为您提供了一个新的元组开始,因此对其进行递归。

这可以如下实现。

from operator import mul
primes = [2, 3, 5, 7, 11]
primes_inorder = dict(zip(primes, primes[1:]))

def my_combinations(primes, r, N, start=None, prod=None):
    """Yield all sorted combinations of length `r`
       from the sorted list `primes`."""
    if start is None:
        start = primes[:r]
        prod = reduce(mul, start)
        if prod > N: return

    yield start

    for i, v in enumerate(start):
        next_v = primes_inorder.get(v, None)
        if next_v is None or (i+1 < r and next_v > start[i+1]):
            continue

        new_prod = prod / v * next_v
        if new_prod > N:
            continue

        new_start = start[:]
        new_start[i] = next_v
        for combination in my_combinations(primes, r, N, start=new_start, prod=new_prod):
            yield combination

【讨论】:

  • 我不确定如何使用它——和以前一样的两个循环?当我这样做时,它似乎输出了太大的元组。
  • @AOAOne 我添加了一些解释——现在有意义吗?它似乎对我有用,而不是我有任何像大型数据集来测试它的东西。
  • 是的,它应该像combinations 一样工作,除了现在你也传递它110
  • 我在 my_combinations(primes,r+1,110) 中用 for combo 调用它,它输出的东西 >=110
  • @AOAOne 啊,错误:它发出了第一个组合,即使那是 >=110。固定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 2013-04-12
  • 2012-03-28
  • 2016-08-18
相关资源
最近更新 更多