"Homemade" infinite precision sum function - python

How would you go about this:
Write your own infinite precision "sum", "product", and "to the power of" functions, that represent numbers as lists of
digits between 0 and 9 with least significant digit first.
Thus: 0 is represented as the empty list [], and 10 is represented as [0,1].
You may assume that numbers are non-negative (no need for negative numbers, or for subtraction).
I have functions to convert to and from.
eg:
iint(5387) == [7, 8, 3, 5] and pint([7, 8, 3, 5]) == 5387
def iint(n):
# list of all digits in the int
digits = [int(x) for x in str(n)]
# reverse the list
digits.reverse()
return digits
def pint(I):
# new int c
c = 0
# iterates through list
for i in range(len(I)):
# add to c digit in the list multiplied by 10^of its position in the list. 1, 10, 100, 1000 ect.
c = c + I[i] * (10 ** i)
return c
# add two infinite integers
def iadd(I, J):
pass
First though would be just convert back to int do the calculation and then back again but that would "gut the question".
Not looking for a complete solution just some pointers on where to start for iadd()because I am completely stumped. I assume after you get iadd() the rest should be simple enough.

For writing your iadd function, one way is to use test-driven development; write your test inputs, and your expected outputs. assert that they're equal, then rewrite your function so it passes the testcase.
In the particular case of needing to add two lists of numbers together, "how would you do that by hand?" (as noted by a comment) is an excellent place to start. You might
starting from the least-significant digit
add individual digits together (including a carry from the previous digit, if any)
carry the "high" digit if the result is > 9
record the result of that addition
loop from step 2 until you exhaust the shorter number
if you have a carry digit "left over," handle that properly
if one of the input numbers has more digits than the other, properly handle the "left over" digits
Here's a code snippet that should help give some ideas:
for d in range(min(len(I),len(J))):
added = I[d] + J[d]
digit = added%10 + carry
carry = added//10
And some testcases to try:
assert iadd([1], [1]) == [2] # 1 + 1 == 2
assert iadd([0,1], [1]) == [1,1] # 10 + 1 == 11
assert iadd([9,1], [1]) == [0,2] # 19 + 1 == 20
assert iadd([9,9,9,9,9], [2]) == [1,0,0,0,0,1] # 99,999 + 2 == 100,001
assert iadd([4,0,2], [9,2,3,4,1]) == [3,3,5,4,1] # 201 + 14,329 == 14,533

Itertools's zip_longest should be very useful to implement the addition operation.
For example:
def iint(N): return [int(d) for d in reversed(str(N))]
def pint(N): return int("".join(map(str,reversed(N))))
from itertools import zip_longest
def iadd(A,B):
result = [0]
for a,b in zip_longest(A,B,fillvalue=0):
result[-1:] = reversed(divmod(a+b+result[-1],10))
while result and not result[-1]: result.pop(-1) # remove leading zeros
return result
a = iint(1234)
b = iint(8910)
print(iadd(a,b)) # [4, 4, 1, 0, 1] (10144)
For the multiplication, you should make sure to keep the intermediate results below 100
def iprod(A,B):
result = []
for iA,a in enumerate(A):
if not a: continue
result = iadd(result,[0]*iA+[a*d for d in B]) # a*d+9 <= 90
return result
print(iprod(a,b)) # [0, 4, 9, 4, 9, 9, 0, 1] 10994940
For the power operation, you'll want to break down the process into a reasonable number of multiplications. This can be achieved by decomposing the exponent into powers of 2 and multiplying the result by the compounded squares of the base (for 1 bits). But you'll need to make a division by 2 function to implement that.
This strategy is based on the fact that multiplying a base raised to various powers, adds these powers:
A^7 * A^6 = A^13
and that any number can be expressed as the sum of powers of two:
13 = 1 + 4 + 8,
so
A^13 = A^1 * A^4 * A^8.
This reduces the number of multiplications for A^B down to 2log(B) which is much less than multiplying A by itself B-1 times (although we'll be dealing with larger numbers).
def idiv2(N):
result = N.copy() or [0]
carry = 0
for i,d in enumerate(reversed(N),1):
result[-i],carry = divmod(result[-i]+carry*10,2)
return result if result[-1] else result[:-1]
def ipow(A,B):
result, a2n = [1], [] # a2n is compounded squares A, A^2, A^4, A^8, ...
while B:
a2n = iprod(a2n,a2n) if a2n else A
if B[0]%2 : result = iprod(result,a2n)
B = idiv2(B)
return result
print(ipow(iint(12),iint(13)))
# [2, 7, 0, 9, 7, 3, 5, 0, 2, 3, 9, 9, 6, 0, 1] 106993205379072
print(len(ipow(a,b))) # 27544 digits (takes a long time)
Further optimization could be achieved by creating a specialized square function and using it instead of iprod(a2n,a2n)

Related

Generate 4 digits number but excluding all the numbers with any 0

I would like to generate 4 digits random number in Python but exclude all the numbers that have a "0" inside. For example, 9230, 2012 will not be accepted since there is a 0.
My code is:
def my_custom_random():
exclude=[0]
randInt = randint(1000, 9999)
return my_custom_random() if randInt in exclude else randInt
def Q3a():
RandomNumber = my_custom_random())
print(RandomNumber)
Q3a()
But this code is not working. Anyone can help me ? Thanks.
Congratulations for not picking the easy but expensive solution, consisting in calling 4 times the random number generator for a number between 1 and 9 inclusive.
we can basically keep your recursive scheme, but delegate the hard work to another function, isBadNumber(). Like this:
def my_custom_random():
randInt = random.randint(1111, 9999)
return my_custom_random() if isBadNumber(randInt) else randInt
To decide whether some number is acceptable or not, we need some auxiliary function that returns the list of digits:
# get at least k digits for a number in some arbitrary base:
def xdigits(k, base, n):
if (n < base):
res = (k-1)*[0] + [n]
else:
res = xdigits(k-1, base, n // base) + [n % base]
return res
Trying:
>>>
>>> q.xdigits(4,10,56)
[0, 0, 5, 6]
>>>
>>> q.xdigits(4,10,123456)
[1, 2, 3, 4, 5, 6]
>>>
>>> q.xdigits(4,10,7702)
[7, 7, 0, 2]
>>>
Thus we can write our isBadNumber() function like this:
def isBadNumber(n):
if ((n < 1111) or (n > 9999)):
return True
ds = xdigits(4, 10, n)
if (min(ds) < 1):
return True # having a zero
return False # passed all tests OK.
Addendum: a method without rejection:
Rejection costs CPU time, so it is always nice if we can do without it. For each of the 4 digits, there are 9 possibilities, 1 to 9 inclusive. Hence the overall number of solutions is 94, hence 6561. As programmers use to do, we can decide to number them from 0 to 6560 inclusive.
So we can pick one of them like this:
>>>
>>> import random
>>> import functools as fn
>>>
>>> random.randint(0,6560)
3952
>>>
If we express this number in base 9 (not 10), we get 4 digits between 0 and 8 inclusive. This is exactly what we need, provided we add 1 to every digit.
>>>
>>> q.xdigits(4,9,3952)
[5, 3, 7, 1]
>>>
We add 1 to every digit, giving [6, 4, 8, 2]. Hence, the 3952-th solution is number 6482.
Going from 3952 thru [5,3,7,1] to 6482 can be done using some simple Python data massaging:
>>>
>>> ds1 = list(map(lambda n: n+1, [5, 3, 7, 1]))
>>> ds1
[6, 4, 8, 2]
>>>
>>> fn.reduce(lambda acc, d: acc*10 + d, ds1)
6482
>>>
So overall the rejection-free code would be like this:
def my_custom_random():
randomRank = random.randint(0, 9**4 - 1)
ds0 = xdigits(4, 9, randomRank)
ds1 = list(map(lambda n: n+1, ds0))
num = functools.reduce(lambda acc, d: acc*10 + d, ds1)
return num
Basically, if you don't want zeros then don't pick zeros. Pick from [1..9] only, so you never pick a zero.
Here is some pseudocode; my Python is not good.
function noZeros()
digits <- [1,2,3,4,5,6,7,8,9] // Zero omitted.
result <- 0
repeat 4 times
result <- 10 * result;
thisDigit <- pick a random entry from digits array
result <- result + thisDigit
end repeat
return result
end function noZeros
I am sure you can write a better version in Python.
I hope it will help you
import random
def my_custom_random():
exclude = 0
digits = [0,1,2,3,4,5,6,7,8,9]
randNumber = random.sample(digits,4) #List of integers Ex. [2,9,1,6]
while exclude in randNumber:
randNumber = random.sample(digits,4)
return map(str,randNumber) #map(str, x) -> transform [2,9,1,6] to ['2','9','1','6']
def Q3a():
randNumber = my_custom_random()
randNumber = "".join(randNumber) # ['2','9','1','6'] to '2916'
print(int(randNumber))
Q3a()
In digits you can omit the 0, so you can write less code. This way you will never have numbers with zero.
def my_custom_random():
digits = [1,2,3,4,5,6,7,8,9]
randNumber = random.sample(digits,4)
return map(str,randNumber)

How to rewrite a program to use recursion?

Just started to deal with recursion - I don’t understand everything in it yet. I think that i don't use a basic conditional, but i don't have any idea how to write it. The program itself works and execute everything i need, but there is no recursion.
The idea of the program is that there is a list in which is neede to sum of every x'th number in the list - x here as a step. If x = 0, then the sum is automatically zero. If x is out of range, then the sum is also 0
def sum_elements(nums, x) -> int::
if x not in range(-len(nums), len(nums)) or x == 0:
return 0
if x > 0:
nums = nums[x - 1::x]
return sum(nums)
return sum_elements(nums[::-1], -x)
if __name__ == '__main__':
print(sum_elements([], 0)) # x = 0 -> 0
print(sum_elements([1, 5, 2, 5, 9, 5], 3)) # 2 + 5 = 7
print(sum_elements([5, 6, 10, 20], -2)) # 10 + 5 = 15
print(sum_elements([5, 6, 10, 20], -20)) # x = -20 -> 0
Recursion is when a function calls itself and there a few (non-formal) rules that are always good to keep in the back of your mind when writing these:
1. The base case.
Every recursion function must have a base case that acts as essentially the end of the stack in the recursive call.
2. Every recursive function abides by the non-base(s) and the base case.
In other words, your code must be written in a way that the function either calls itself, or it terminates the recursive call. You can either do this by doing if and else statements, or only writing if statements to catch the base case(s).
3. The input of the function should keep in mind the state of the previous function.
In math, you might remember functions that call themselves (syntax switched for the case of explanation):
f(x)_(n=0) = f(x)_(n=1) + 10
which becomes:
f(x)_(n=1) = ( f(x)_(n=2) + 10 ) + 10
and so on. In essence, you are writing this with code and setting a base case that might say (for the example above, i.e.) "stop when n is 10". If that was the case, you should notice the cascading effect when we are layers deep into that function and when f(x)_(n=10) makes its appearance (and lets says returns 0 + 10) how we would have a final form of f(x)_(n=0) = 0 + 10 + 10 + 10 + ....
So for this function you instead have two inputs, nums and x. These inputs are what we will be modifying as we go down the recursion's stack.
1. Writing our base case.
Writing the base case is typically the easiest part of writing a recursion function. We know, for your problem, the following cases must be caught:
If x is not in the range of the length of nums, then we must return 0.
If len(nums) is 0, then we should return 0.
So lets begin:
def sum_elements(nums, x) -> int:
if len(nums) == 0 or not x in range(-len(nums), len(nums)):
return 0
Notice, however, that range(len([1, 2])) will return range(0, 2) but list(range(0, 2)) will return [0, 1]. Therefore, we must ensure to add a 1 to our len(nums) so that we can truly see if x is within the proper range:
def sum_elements(nums, x) -> int:
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
Notice that range(-len(nums), len(nums) + 1) for when nums = [1, 2, 3] is equals to range(-3, 4), but list(range(-3, 4)) is equals to [-3, -2, -1, 0, 1, 2, 3]. So therefore, we do not need a -len(nums) + 1 or -len(nums) - 1.
Once we have figured out the base case, we can start working on our actual function. At this point we have done #1 and a portion of #2, but we now must write our non-base(s) case(s).
2. Identifying our other-case(s):
As written in #2, our function input is what is dynamically changing as we go down our function stack. Therefore, we need to think about how we need to modify nums and/or x to fit our purposes. The first thing you should look at, however, is what would happen if we only change one of those variables as we go down the stack.
Keep nums constant, modify x: We know our base case ensures x stays within the constrain of the length of nums in both the positive and negative direction, which is good. However, we must increment x every time the function runs by the original x, or x_0. If we create the function and on every call say x + x, we are not adding the original x to itself, but rather adding the newer x's to itself. This is a problem. Take the following for example:
def sum_elements(nums, x) -> int:
print(nums, x)
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case. We must differentiate between positive x, and negative x.
if x > 0:
# Since x is an index that starts at 1, not 0, we must do x-1.
number = nums[x - 1]
else:
# For negative values of x this does not apply. [1, 2][-2] = 1
number = nums[x]
return number + sum_elements(nums, x + x)
Notice how we get:
# [NUMS] x
[1, 2, 3, 4, 5, 6] 2
[1, 2, 3, 4, 5, 6] 4
[1, 2, 3, 4, 5, 6] 8
# OUTPUT
6
and how the x value on the third call is 8. This is no bueno. The more you practice recursion, the more intuitive this concept will become on noticing how changing a certain input might not be the best. You ought to think: "what will this value be when the function continues down the stack?"
Keep x constant, modify nums: If we do this way we should be certain that we will not have issues with the value of x. The issue, then, becomes how we will modify the nums list and use x for our advantage. What we do know, is that x can be technically used as an index, as demonstrated above. So, therefore, what if instead of modifying the index, we modify the list in which that index takes from? Take the following for example:
nums = [1, 2, 3, 4]
x = 2
print(nums) # > [1, 2, 3, 4]
print(nums[x - 1]) # > 2
nums = nums[x:] # > [3, 4]
print(nums[x - 1]) # > 4
So it does seem like we can modify the list and keep a constant x to retrieve the information we want. Awesome! In such case #2 is the way to go.
3. Writing our other-case(s).
So now we will try to now write a function that keeps x constant, but modifies nums. We have a general idea from the code above, and we know from the previous point that we will have to deal with -x and x differently. Therefore, lets write something:
def sum_elements2(nums, x) -> int:
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case.
if x >= 0:
number = nums[x - 1]
nums = nums[x:]
else:
number = nums[x]
# Not sure what goes here.
return number + sum_elements(nums, x)
If we test the function above, it seems that it works for any positive x, but won't work for negative values of x. It makes sense, however, that whatever we do to the positive side, we must do the opposite to the negative side. If we try to use nums = nums[:x] we very quickly realize it works. Our final function becomes:
def sum_elements(nums, x) -> int:
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case.
if x >= 0:
number = nums[x - 1]
nums = nums[x:]
else:
number = nums[x]
nums = nums[:x]
return number + sum_elements(nums, x)
Running Examples
If we run examples with the above function, we get:
print(sum_elements([1, 2, 3, 4, 5, 6], 2)) # > 2 + 4 + 6 = 12
print(sum_elements([], 0)) # > 0
print(sum_elements([1, 5, 2, 5, 9, 5], 3)) # > 7
print(sum_elements([5, 6, 10, 20], -2)) # > 15
print(sum_elements([5, 6, 10, 20], -20)) # > 0
Maybe this approach can help you understand.
It starts from the first element and sums the rest every x ones.
That is my assumption, as you haven't provided an input and its desired output as an example.
In case you need to start from the xth element the code can be easily modified, I leave it to you to experiment with it.
def sum_elements(nums, x) -> int:
if x>0 and x<=len(nums):
return nums[0] + sum_elements(nums[x:], x)
return 0
lst = [1, 2, 3, 4, 5, 6]
print(sum_elements(lst, 2))
print(sum_elements(lst, 3))
print(sum_elements(lst, 0))
produces
9
5
0
Note: it just demonstrates recursion, but it's not optimal for a number of reasons.
Also it discards negative values of x

How to divide an unknown integer into a given number of even parts using Python

I need help with the ability to divide an unknown integer into a given number of even parts — or at least as even as they can be. The sum of the parts should be the original value, but each part should be an integer, and they should be as close as possible.
Parameters
num: Integer - The number that should be split into equal parts
parts: Integer - The number of parts that the number should be split
into
Return Value
List (of Integers) - A list of parts, with each index representing the part and the number contained within it representing the size of the part. The parts will be ordered from smallest to largest.
This is what I have
def split_integer(num,parts):
if (num < parts):
print(-1)
elif (num % parts == 0):
for i in range(parts):
print(num // parts),
else:
parts_remaining = parts - (num % parts)
quotient = num // parts
for i in range(parts):
if (i >= parts_remaining):
print(quotient + 1),
else:
print(quotient),
split_integer(10, 1)
This is the sample tests
import unittest
class Test(unittest.TestCase):
def test_should_handle_evenly_distributed_cases(self):
self.assertEqual(split_integer(10, 1), [10])
self.assertEqual(split_integer(2, 2), [1,1])
self.assertEqual(split_integer(20, 5), [4,4,4,4,4])
Examples of the expected output
num parts Return Value
Completely even parts example 10 5 [2,2,2,2,2]
Even as can be parts example 20 6 [3,3,3,3,4,4]
I am getting the error
Failure
AssertionError: None != [10]
The first problem is that you are printing your results instead of returning them. By default, in Python, any function that does not explicitly return anything will return None.
In any case, there is a more concise way, using comprehensions:
def split_integer(num, parts):
quotient, remainder = divmod(num, parts)
lower_elements = [quotient for i in range(parts - remainder)]
higher_elements = [quotient + 1 for j in range(remainder)]
return lower_elements + higher_elements
Or simply,
In [1]: n,p=20,6
In [2]: c,r=divmod(n,p)
In [3]: [c]*(p-r) + [c+1]*r
Out[3]: [3, 3, 3, 3, 4, 4]
This problem is very similar to the "giving change" problem.
Let us start by looking at the simplest scenario of split(10, 1) where you're dealing with a partition size of 1 i.e parts = 1, an intuitive solution would be: partition = [10]. Of course, this assumes that the remainder = 0 and parts = 1 or 0.
If that is a generic idea of a base case, then the total partitions can be calculated by way of recursion where both the num and parts are continuesly reduced as shown below:
def split_integer(num, parts):
"""
split_integer(integer, parts) -> [ value[, values] ]
divides an integer into an ""even as can be"" number of parts.
>>> split_integer(10, 1)
[10]
>>> split_integer(2, 2)
[1, 1]
>>> split_integer(20, 5)
[4, 4, 4, 4, 4]
>>> split_integer(10, 5)
[2, 2, 2, 2, 2]
>>> split_integer(20, 6)
[3, 3, 3, 3, 4, 4]
>>> split_integer(5, 4)
[1, 1, 1, 2]
"""
lower_bound, remainder = divmod(num, parts)
sub_partition = [lower_bound ] * (parts - remainder)
num -= len(sub_partition) * lower_bound
if remainder:
sub_partition += split_integer(num, remainder)
return sub_partition
if __name__ == "__main__":
import doctest
doctest.testmod()

Finding the odd integer that does not form the pair in the list

I am given a problem to solve ! which is
A non-empty array A consisting of N integers is given. The array contains an odd number of elements, and each element of the array can be paired with another element that has the same value, except for one element that is left unpaired.
For example, in array A such that: A[0] = 9 A[1] = 3 A[2] = 9 A[3] = 3 A[4] = 9 A[5] = 7 A[6] = 9
the elements at indexes 0 and 2 have value 9,
the elements at indexes 1 and 3 have value 3,
the elements at indexes 4 and 6 have value 9,
the element at index 5 has value 7 and is unpaired.
Write a function:
def solution(A)
that, given an array A consisting of N integers fulfilling the above conditions, returns the value of the unpaired element.
For example, given array A such that:
A[0] = 9 A[1] = 3 A[2] = 9
A[3] = 3 A[4] = 9 A[5] = 7
A[6] = 9
the function should return 7, as explained in the example above.
Write an efficient algorithm for the following assumptions:
N is an odd integer within the range [1..1,000,000];
each element of array A is an integer within the range [1..1,000,000,000];
all but one of the values in A occur an even number of times.
I think I am only half way to solve the problem:
def findOddItem(A):
for i, item in enumerate(A): # look to left not immidiate one
if A[i] != A[i - 2]:
print A[i]
but this looks like printing the wrong result..
I would go with reduce() (moved to functools.reduce() in Python 3.x) in combination with operator.xor():
# Uncomment for Python 3.x:
# from functools import reduce
import operator
def solution(A):
return reduce(operator.xor, A)
arr = [9, 3, 9, 3, 9, 7, 9]
print(solution(arr)) # 7
It's an, as clean as it gets, O(n) solution.
You could use "or" bitwise operator. Since all elements occur twice except one element they would cancel each other leaving the element that has occurred only once.
def findSingleOccurance( arr, n):
res = arr[0]
# Do XOR of all elements and return
for i in range(1,n):
res = res ^ arr[i]
return res
Time complexity O(n) Space Complexity O(1).
Hope this helps.
Since there is no condition that all but one elements occur twice, I guess it could also mean 4, 6, ... , times.
In this case, I would rather use numpy.bincount to see which integer has an odd count.
a = [1,1,2,2,3,3,5,3,3,4,5,5,5,10,10]
a_cnt = list(numpy.bincount(a))
for i in a_cnt:
if i != 0 and i%2 == 1:
print(a_cnt.index(i))
# 4
You could use "xor" bitwise operator. Since all elements occur twice except one element they would cancel each other leaving the element that has occurred only once.
def SingleOccurance( arr, n):
result = arr[0]
# Do XOR of all elements and return as 'a' xor 'a' is 0 and except single
# occured number rest will turn to 0 and 'a' xor 0 is 'a'
for i in range(1,n):
result = res ^ arr[i]
return result
Or
We can sum the bits in the same positions for all the numbers and take modulo with 3. The bits for which sum is not multiple of 3, are the bits of number with a single occurrence.
Let us consider the example array {5, 5, 5, 8}. The 101, 101, 101, 1000
Sum of first bits%3 = (1 + 1 + 1 + 0)%3 = 0
Sum of second bits%3 = (0 + 0 + 0 + 0)%0 = 0
Sum of third bits%3 = (1 + 1 + 1 + 0)%3 = 0
Sum of fourth bits%3 = (1)%3 = 1
Hence number which appears once is 1000
Code:
INT_SIZE = 32
def getSingle(arr, n) :
# Initialize result
result = 0
# Iterate through every bit
for i in range(0, INT_SIZE) :
# Find sum of set bits at ith position in all array elements
sm = 0
x = (1 << i)
for j in range(0, n) :
if (arr[j] & x) :
sm = sm + 1
# The bits with sum not multiple of 3, are the
# bits of element with single occurrence.
if (sm % 3) :
result = result | x
return result

I want to know how to add to digits together in a list. Say the number is 10. I need it to add 1 + 0 to the new list

I want to know how to add to digits together in a list. Say the number is 10. I need it to add 1 + 0 to the new list. If the item in the list is 11 it needs to add 2 to the list
def main():
#Define List
mylist = [4,5,5,2,7,2,0,4,1,2,3,4,5,6,7,8]
print(mylist)
newlist = []
for each in mylist:
if (each % 2 == 0):
newlist.append(each)
else:
newlist.append(each + each)
for each in newlist:
if each >= 10:
newlist.append(each + each)
print(newlist)
main()
To get the digit sum of a number, you should convert the number to a string, loop over the string, and add all chars together (after converting them to int again):
def get_digit_sum(num):
return sum(int(x) for x in str(num))
To do this for a list of numbers, you should use list comprehension:
>>my_nums = [11, 22, 56, 345]
>>digit_sums = [get_digit_sum(x) for x in my_nums]
>>print(digit_sums)
[2, 4, 11, 12]
This is also possible to do in one expression:
>>my_nums = [11, 22, 56, 345]
>>digit_sums = [sum(int(x) for x in str(num)) for num in my_nums]
As per abarnet's comment, you may want the number 345 to be converted to 3+4+5=12, and the convert 12 to 1+2=3. This can be done using recursion. By using a max_digits parameter, you can specify the maximum number of digits in the returned number.
def get_digit_sum(num, max_digits=1):
d = sum(int(x) for x in str(num))
if len(str(d)) > max_digits:
return get_digit_sum(d)
return d
or a bit shorter:
def get_digit_sum(num, max_digits=1):
d = sum(int(x) for x in str(num))
return get_digit_sum(d) if len(str(d)) > max_digits else d
Both of the above functions would then yield:
>>my_nums = [11, 22, 56, 345]
>>print [get_digit_sum(x) for x in my_nums]
[2, 4, 2, 3]
It looks like your code is trying to do a little bit more than what you describe - in particular, you double any odd numbers. Because you're doing two things to each number (possibly double, sum the digits), you don't want to put it in the list until both steps are done. Instead do something like this:
for each in mylist:
if each % 2 != 0:
each *= 2
if each >= 10:
each = # sum of digits
newlist.append(each)
There's a couple of ways you could sum the digits. You can use divmod to get the quotient and the remainder of the number divided by 10 - the remainder is the units column, the quotient is every column to the left of that:
if each >= 10:
q, r = divmod(each, 10)
each = q + r
the other way is to get the string representation, which lets you iterate over every digit, convert it back to a number and add them:
if each >= 10:
each = sum(int(d) for d in str(each))
this is possibly easier to understand It is, however, a fair bit slower - which might matter if you have a very large amount of input.
These two approaches do work differently if you end up with any three or more digit numbers in the list - for 110, the divmod version will do 11 + 0 = 11, while the string version will do 1 + 1 + 0 = 2.
Also note that neither is guaranteed to end up with a single-digit number in the end - for 99, both of these will give you 18. If you want that further reduced to 9, you can change the if to a loop:
while each >= 10:
each = sum(int(d) for d in str(each))
to do this for the divmod version, you could put it into a recursive function instead:
def digit_sum(number):
q, r = divmod(number, 10)
if q > 10:
q = digit_sum(q)
return q+r
Making the same change to the divmod version as the string version appears to give the same answer in every case I've tried, but I have no idea if this is guaranteed to be the case.
> [int(d) for d in str(123)]
[1, 2, 3]
Try this:
A function that sums the digits for a given number:
def sum_of_digits(num):
return sum([int(x) for x in str(num)])
And a list comprehension to apply it to the entire list:
newlist=[sum_of_digits(number) for number in mylist]
I believe I know what you are going for. If the value is even and less than 10 add it to the new list, if the value is odd then double it and if that is less than 10 add it to the new list. Now if the value is greater than 10 then take the sum of all the digits and add it to the list.
I am sure there is a better way to do this, but this is what I came up with.
list = [4,5,5,2,7,2,0,4,1,2,3,4,5,6,7,8]
newlist = []
for i in list:
if i % 2 == 0 and len(str(i)) > 1:
newlist.append(sum([int(x) for x in str(i)]))
elif i % 2 == 0:
newlist.append(i)
elif len(str(i*2)) > 1:
newlist.append(sum([int(x) for x in str(i*2)]))
else:
newlist.append(i*2)
print newlist
input: [4, 5, 5, 2, 7, 2, 0, 4, 1, 2, 3, 4, 5, 6, 7, 8]
outcome: [4, 1, 1, 2, 5, 2, 0, 4, 2, 2, 6, 4, 1, 6, 5, 8]

Categories