for example def f(n):
and I wanna check whether the sum of the numbers within n
equal to 100 whether it is in 1s, 2s, 3,s 4s, 5s and so on, depending on the length of n
.
f(5050)
>>> True
This tests whether 5 + 0 + 5 + 0 == 100
and whether 50 + 50 ==100
and if any are true, it returns True
.
Whether it tests in 1s, 2s 3s 4s and so on, depends on the length of the number. For example a number with a length of 5 can only be tested in 1s.
f(12345)
>>> False
This tests whether 1 + 2 + 3 + 4 + 5 == 100
and only that.
If the length of n
was 15, it would test the digits in 1s, 3s and 5s.
and finally one more example:
f(25252525)
>>> True
This would test whether 2+5+2+5+2+5+2+5 == 100
and 25+25+25+25==100
and whether 2525+2525==100
So n
, which has a length of 8 would be tested in 1s , 2s , and 4s. It cannot be tested with 3s and 5s because the length of all the digits within the number being summed up must be the same.
I hope I was able to explain what I'm after. Usually I would post what I've tried but I have no idea how to iterate over the digits of a number in such a way
The below approach uses generator to split the integer, and no integer <-> string
conversion.
This will likely be the most efficient approach of the ones currently listed.
import math
# Define a generator that will split the integer v into chunks of length cl
# Note: This will return the chunks in "reversed" order.
# split(1234, 2) => [34, 12]
def split(v, cl):
while v:
(v,c) = divmod(v, 10**cl)
yield c
def f(v):
# Determine the number of digits in v
n = int(math.log10(v)) + 1
m = int(math.sqrt(v))
# Check all chunk lengths in [1, sqrt(v)]
for cl in range(m):
# Skip the chunk lengths that would result in unequal chunk sizes
if n % (cl+1): continue
# Create a generator, to split the value v into chunks of length cl
chunks = split(v, cl+1)
# If the sum of the chunks is 100, print a message and return True
if sum(chunks) == 100:
print("sum = 100 with chunklength: %d" % cl)
return True
# If we get here, none of the chunk lengths result in a sum of 100, return False
return False
print(f(5050)) # True (cl=2)
print("---")
print(f(12345)) # False
print("---")
print(f(25252525)) # True (cl=2)
print("---")
Output:
sum = 100 with chunklength: 2 True --- False --- sum = 100 with chunklength: 2 True ---
Without comments and debugging print
:
import math
def split(v, cl):
while v:
(v,c) = divmod(v, 10**cl)
yield c
def f(v):
n = int(math.log10(v)) + 1
m = int(math.sqrt(v))
for cl in range(m):
if n % (cl+1): continue
if sum(split(v, cl+1)) == 100: return True
return False
print(f(5050)) # True
print(f(12345)) # False
print(f(25252525)) # True
Assuming that the numbers are always positive integers, you can just divmod()
them by 10
until you get to zero:
def int_iter(number):
while number > 0:
number, last_digit = divmod(number, 10)
yield last_digit
Note that gives you the digits in reverse order. That doesn't matter if you're just adding them together, though.
You can pass this around or use it in a for
loop, like any other iterable:
digit_sum = sum(int_iter(number))
If you really need a sequence, just pass it to list()
:
digit_list = list(int_iter(number))
And if you need them in most-significant-first order, pass it to reversed()
:
digits_msf = reversed(list(int_iter(number)))
EDIT:
Whoops, I missed…about half of the question. Things are rather more complicated. You'll need a function to get all the factors of a number—I'm sure there are plenty, so I'll leave that as an excercise for you. Let's assume there's a function factors(number)
that returns an iterable of all a number's factors (including nonprimes and 1, but not number
itself). We'll also use the int_iter()
from my original answer, an int_from_digits()
that takes a list of digits and returns a single integer (sort of like the inverse of int_iter()
), and something called grouper()
from the itertools
recipes .
from itertools import zip_longest
def int_from_digits(digits):
"Generate an integer from an iterable of single decimal digits"
# int_from_digits([4, 0, 2, 8, 9]) --> 40289
# int_from_digits([]) --> 0
number = 0
for digit in digits:
number *= 10
number += digit
return number
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
def digit_subsequences(number):
digits = list(reversed(list(int_iter(number))))
for factor in factors(number):
for digit_grouping in grouper(digits, factor):
yield int_from_digits(digit_grouping)
Finally, armed with all these tools (or rather, one tool and its dependencies), we can perform your check with a simple comprehension and a call to any()
:
any(digit_subsequence == 100 for digit_subsequence in digit_subsequences(number))
One possible way, separated into functions for each logical step :
def get_factors(n):
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
l
factor of n
, split str(n)
into chunks of length l
: def get_chunks(str_n, chunk_size):
total_size = len(str_n)
return [int(str_n[i:i+chunk_size]) for i in range(0, total_size, chunk_size)]
def f(n):
factors = get_factors(n)
for l in factors:
if sum(get_chunks(str(n), l)) == 100:
return True
return False
I think this does the trick. Not sure though:
def f(n):
s = str(n)
l = len(s)
for n in (n for n in range(1, l + 1) if l % n == 0):
ints = [int(''.join(x)) for x in zip(*[iter(s)]*n)]
if sum(ints) == 100:
return True
return False
The zip
thing comes from here . It's a little weird but it allows me to split the string up into n-length segments and then join it back together so I can apply an int
mapping and then a sum
reduction.
The generator just gets all positive divisors of l
from 1
to l
, both inclusive. There may be faster ways of doing it for large n
using math.sqrt
and divmod
.
def factors(num):
yield 1
for i in range(2, num - 1):
if num % i == 0:
yield i
def pieces(string, sz):
for i in range(0, len(string), sz):
yield string[i:i+sz]
def check_sum(string):
for f in factors(len(string)):
pcs = pieces(string, f)
if sum([int(x) for x in pcs]) == 100:
print 'True'
return
print 'False'
>>> check_sum('5050')
True
>>> check_sum('25252525')
True
>>> check_sum('12345')
False
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.