4

在 Python 中迭代整数的最佳实践是什么?我发现我需要经常这样做,通常会产生冗长的结果。例如,这是我为Project Euler问题编写的两个函数:

def is_permutation_of(n, m):
    """ Return True if n is a permutation of m, else False
    """
    if len(str(n)) != len(str(m)):
        return False
    for d in str(n):
        if d not in str(m):
            return False
    return True

还有一个:

def has_even_digit(n):
    """ Return True if n has an even digit, else False
    """
    evens = ['0', '2', '4', '6', '8']
    for e in evens:
        if e in str(n):
            return True
    return False

除了冗长之外,1) 必须有与每个类型转换相关的计算开销,以及 2) 感觉完全不优雅。有没有另一种方法来处理这个问题?我是否以完全错误的方式处理这些函数,即我是否应该不必遍历整数?

谢谢你的帮助。

4

8 回答 8

3

我个人觉得for e in str(n)非常具有可读性。

我确实发现不那么令人赏心悦目的是对str(n)内部循环的重复调用(其中n是不变的)。

无论如何,我会以完全不同的方式实现这两个功能

def is_permutation_of(n, m):
   return sorted(str(n)) == sorted(str(m))

def has_even_digit(n):
   if n == 0:
      return True
   while n != 0:
      if n % 2 == 0:
         return True
      n //= 10
   return False
于 2013-01-30T18:24:55.787 回答
3

我更喜欢我的变体而不是你的is_permutation_of

def is_perm(a,b): return sorted(str(a)) == sorted(str(b))

我认为这对has_even_digit

def has_even_digit(n):
    evens=set(['0', '2', '4', '6', '8'])
    return any(c in evens for c in str(n))

或者,甚至使用元组而不是集合:

def has_even_digit(n):
    return any(c in ('0', '2', '4', '6', '8') for c in str(n))

编辑

从评论线程中,我认为您正在寻找这样的东西:

# pseudo code -- don't use -- not syntactically correct
for d in 123456:      # integer
   # do something with each digit...

这不起作用,因为整数不支持 Python 中的迭代。此外,没有真正需要像整数迭代这样的东西,因为它是如此地道且易于使用字符串来完成。

这是一个 Python 框架,用于处理字符串但生成单个整数:

for d in [int(c) for c in str(123456)]:
    # d is a left (most significant) to right integer digit - do what you want with it...

如果您想要从右到左的相同数字:

for d in [int(c) for c in str(123456)[::-1]]:
    # Now right (least significant digit) to left (most significant digit)

将这两个简单的情况与整数或长整数的实际数学进行比较:

def int_iter(n,reverse=False):
    rtr=[]
    if not isinstance(n, (int,long)):
        raise ValueError('n must be int or long')

    while n:
        rtr.append(n%10)
        n/=10

    if reverse:
        return rtr[::-1]    
    else:
        return rtr  

使用字符串确实容易得多,而且可能更快。如果您需要超快的速度,请在 C 中进行。

于 2013-01-30T18:28:05.010 回答
2
def is_permutation_of(n, m):
    return sorted(n) == sorted(m)

evens=re.compile('[02468]')
def has_even_digit(n):
    return evens.search(str(n))
于 2013-01-30T18:31:26.970 回答
1

如果您的数字不是“大量” - 即使事情停止,那么您可以使用您的has_even_digitas:

>>> a = 123456789
>>> any(i % 2 == 0 for i in map(int, str(a)))
True

如果做不到这一点,优化将是对1自身进行按位 - 因为如果设置了第一位,则任何可以用二进制表示的东西都必须是奇数。虽然这与“整数”有关 - 而不是数字。

于 2013-01-30T18:25:26.957 回答
0

为了迭代偶数位,您可以使用range 的step参数:

range(start, end, step)

因此,在您的代码中,您可以执行以下操作:

for e in range(0, 8, 2):

于 2013-01-30T18:26:59.833 回答
0

您可以创建一个生成器:

def digits(num):
    while num > 0:
        yield num % 10
        num /= 10
于 2013-01-30T18:27:04.033 回答
0

如果您将 is_permutation_of 的计算成本存储到单独的变量中,则可以轻松降低它们的计算成本。

def is_permutation_of(n, m):
    """ Return True if n is a permutation of m, else False
    """
    sn = str(n)
    sm = str(m)
    if len(sn) != len(sm):
        return False
    for d in sn:
        if d not in sm:
            return False
    return True
于 2013-01-30T18:29:59.203 回答
0
def has_even_digits(n):
    return bool(set('02468') & set(str(n)))
于 2013-01-30T18:37:39.867 回答