What is Pythonic or the best way to iterate over an integer?

What is the best practice for integer iteration in Python? I find that I need to do this often, usually with detailed results. For example, here are two functions that I wrote for Project Euler problems:

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 

And further:

 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 

In addition to the verbosity: 1) there should be estimated costs associated with the conversion of each type, and 2) it just feels completely inelegant. Is there any other way to solve this problem? I deceive these functions completely incorrectly, i.e. Shouldn't I ever iterate over an integer?

Thanks for any help.

+4
source share
8 answers

I prefer my option over your is_permutation_of :

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

And I think this is better for 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)) 

Or even use a tuple rather than a set:

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

Edit

From the comment stream, I think you're looking for something like this:

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

This does not work because integers do not support iteration in Python. Also, there is no real need to have something like a whole iteration, since it is so idiomatic and easy to use with strings.

Here is the Python framework that does this with strings, but produces a single integer digit:

 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... 

If you need the same number from right to left:

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

Compare these two simple cases by doing them with actual math with integer or long:

 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 

Actually it is much easier to use strings and probably faster. If you need high speed, do it in C.

+3
source

I personally find for e in str(n) very readable.

What seems less pleasant to my eyes is the repeated calls inside str(n) inside the loops (where n is invariant).

Anyway, I would perform both functions differently.

 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 
+3
source
 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)) 
+2
source

If your numbers are not "massive", i.e. stopping things you can use has_even_digit like:

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

Otherwise, the optimization would be bitwise with 1 itself - since everything that appears to be binary should be odd if the first bit is set. Although this refers to the "integer" and not to numbers.

+1
source

To iterate over even numbers, you can use the range step parameter:

range(start, end, step)

So in your code you can do:

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

0
source

You can create a generator:

 def digits(num): while num > 0: yield num % 10 num /= 10 
0
source

The estimated costs for is_permutation_of are easily mitigated if you just store them in separate variables.

 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 
0
source
 def has_even_digits(n): return bool(set('02468') & set(str(n))) 
0
source

All Articles