4. digit_sum **challenge**


#1


UPDATED (unsolved)
I am trying to solve the challenge enclosed in the Hint. It asks to use % or // within a pattern to isolate all of the digits given in a number, and then to add them to a total. Here is the link:


https://www.codecademy.com/en/courses/python-intermediate-en-rCQKw/0/4?curriculum_id=4f89dab3d788890003000096#


I tried to use floor divide to isolate each digit by dividing it by 10 * 3, then, * 2, then * 1, as appropriate. Here is my attempt:


numbers = []

def digit_sum(n):
    s = str(n)
    l = len(s)
    if n > 0:
        for d in range(l):
            number = int(n // (10 * (l - (int(s[d]))))
            print number
            numbers.append(number)
        print sum(numbers)


The error reads:
Did you create a function called digit_sum? Your code threw a "global name 'digit_sum' is not defined" error.

and then

File "python", line 16
print number
^
SyntaxError: invalid syntax

If I delete "print number", the same occurs for the following line.

Any advice helps. Also, if you have recommendations of how to go about the same task using % instead.

Thanks mtf for all your suggestions!


#2

each is a string. Try, int(each), maybe?

Example using modulo:

def digit_sum(n):
    sum = 0
    while n > 0:
        sum += n % 10
        n //= 10
    return sum
print digit_sum(1234)

#3

You were right about that! But I think I need to remove "each" entirely.. I am trying to use it for its index, rather than its value.

That being said, how do I retrieve the index of a digit within a number?


#4

The simplest way would be use a range, then the iterator variable is the index.

s = str(n)
t = len(s)
for i in range(t):
    # s[i]

Now i is the index.


#5

If we want to have index and value, we can use Python's enumerate() function:

for i, item in enumerate(s):    # s from above
    print "%s : %s" % (i, item)

#6

Thank you this is of great help. Did not fully understand this concept at first. For some reason, now I am getting syntax errors to follow.. Here is my altered solution.

numbers = []

def digit_sum(n):
    s = str(n)
    l = len(s)
    if n > 0:
        for d in range(1, l):
            number = int(n // (10 * (l - (s[d] + 1)))
            print number
            numbers.append(number)
        print sum(numbers)

The error I receive is:

Did you create a function called digit_sum? Your code threw a "global name 'digit_sum' is not defined" error.

and then

File "python", line 16
print number
^
SyntaxError: invalid syntax

If I delete "print number", the same occurs for the following line.


#7

Still a string. Try, int(s[d])


#8

Good point. Unfortunately still getting the same error. :sweat:


#9

Python indicates the error on the first line that it cannot run, meaning the error is before line 16, not on line 16. It's actually something in line 15 causing the problem.

First problem to surface is that numbers is not defined. I rewrote the following:

def digit_sum(n):
    if n > 0:
        numbers = []
        s = str(n)
        k = len(s)    # k doesn't look like a 1.

Trying a number of things and getting a divisionByZeroError. Perhaps it will help if we go over the math sense of this line:

        for d in range(1, k):
            number = int(n // (10 * (k - (s[d] + 1)))

Please walk us through the math. Thank you.


#10

Thank you. I didn't realize the empty list had to be within the same function (does it always?).

Here is my understanding of the following lines. I altered them slightly.

for d in range(l):
            number = int(n // (10 * (l - (int(s[d] + 1))))

for d in range(l):

loop as many times as the length of inputted string

number = int(n // (10 * (l - (int(s[d] + 1))))

create variable "number" to hold isolated digit of inputted number
isolate each digit by dividing the inputted number by 10 * (length of string - (index of number + 1))
i.e. for 1234, divide by 10 * (4 - 1), then 10 * (4 - 2), then 10 * (4 - 3), then 10 * (4 - 4)
then convert each product to an integer to get rid of the decimal points

Now it occurs to me that I should be dropping the left-most digit as I loop. Right now this should yield (if I am not mistaken): 1, 12, 123, 1234

So I would have to convert it back into a string and then somehow .pop all digits preceding the digit in question...

However, this still would not account for the error. I would just end up with a REALLY big number, right?

Is there a better way to approach this?


#11

@samsara330

No, it does not. Though if the function in question is to be the only thing to access that particular information encapsulating it in the function is a must.

Also, if you use a global variable in a function you have to do some special set-up before you can reassign the value most of the time.

Python Code Example:

hold = 1

def change_hold():
    global hold
    hold += 1

print(hold)
change_hold()
print(hold)

Depending on what version of python you are using you will have to do the above to get a global variable into the proper scope for the function to work right.

----------------------------------------------

(For the Challenge)

On to your math,
you need two separate parts for each iteration of your loop. Currently you only have one.

The two things that they are having you do is modulus (remainder) division and floor division.

Ok, now % is called a modulus in python, it does remainder division.

// or / is floor division depending on the python version you are using. Ensure you are using the correct one for your version.

Using these two functions you will be able to complete this task. If you need another hint as to how to use them ask and we will provide you with what you need.

You can totally implement this but it requires a bunch more code than popping out the right most digit and moving left.

Also your most recent code is off the mark completely for what you are trying to implement. There should not be any conversions to str needed.

Again, if you need any tips ask away.


#12

Probably. I was trying so hard to make your code work, all the while seeing that it was maybe a lost cause owing to complication. I didn't want to say that, though, at least not until I give it a try. Going by what @zeziba has added, it might be worthwhile to start over.

  1. initialize an accumulator variable to 0
  2. set up a while loop for n > 0
  3. accumulate the modulo of n and 10
  4. floor divide n by 10
  5. complete loop
  6. return accumulated total
  7. print the return

#13

I think nobody pointed out yet that there are 5 open and 4 closed brackets.


#14

Thanks very much for this. I'll try to revisit the challenge.. if I'm stuck scratching my head I'll be sure to let you know!

You really are opening up another can of worms for me. I didn't consider the version of Python that I was learning! :sweat: Nevertheless, thanks for this.


#15

For some reason this was a difficult concept for me to grasp, but I finally get it! (Not understanding \\ didn't help either)

Here is my code:

def digit_sum(y):
    count = 0
    while y >= 10:
        count += (y % 10)
        y = y // 10
    else:
        count += y
        print count

Hope you like! If you feel it could be more efficient, do let me know.

Also, even though the code is running properly and is printing in the console as expected, I am STILL getting errors saying that is isn't functioning properly. Oh well! So long as I know... right?

Thanks so much @mtf (!!) @zeziba and @eveat for your time.

I really hate not understanding errors.


#16

@samsara330

You are so very close,

Should be more like,

Python Code:

def digit_sum(number):
    count = 0
    while number > 0: # Take note on the fact we go to 0 here
        count += number % 10
        number = number // 10
    return count

Your code is spot on but it is more readable like the above. You will mostly refrain from using while/for loops with the else clause in most of your coding adventures.

Later you will be able to do things like

Python Code:

def digit_Sum(number, total=0):
    return total if number <= 0 else digit_sum(number // 10, total+(number % 10))

Again, great job!


#17

The course modules here are 2.7.x, Some 3.x will still work in 2.7.x, but some won't, or will work differently than it would in 3.x. Take for instance, range(). In 2.7.x it generates a list; in 3.x it generates an iterator.

When reading documentation to help with these modules, follow the 2.7.x discussion, and maybe along the way the 3.x and build up a store of differences as you go. This runs counter to the recommended learning path, by modern thinking, but we shouldn't be distracted by it. We are only doing a walk-through here,


#18

I didn't realize you can modulo a number by a bigger number! e.g. 5 % 10 = 5
I will have to read into this more bc I don't get how it works, but it definitely eliminates the need to perform different calculations for numbers > and < than 10.

Awesome. I feel like this is the best way to learn. Try to figure out the answer and have ppl show you how to improve it. Thanks :slight_smile:

Wow and that last demonstration is very cool. Can't wait for the learnings ahead!


#19

Totally agree with this sentiment. That is a beautiful demonstration of a recursive function.

Beautifully synthesized into a declarative statement the compiler will have no trouble with.


#20

@samsara330 @mtf

Better be careful, there is a rabbit hole coming up!!

My current 'thing' is doctests, learn them love them(they lead into unitests.)

Below I demonstrate how to use doctests.

Python Code Example:

def digit_Sum(number, total=0):
    """
    Function to calculate the sum of all digits in a integer number!    

    >>> digit_sum(434)
    11
    >>> digit_sum(5132)
    11
    >>> digit_sum(1712)
    11
    >>> digit_sum(922919551)
    43
    """
    return total if number <= 0 else digit_sum(number // 10, total+(number % 10))

if __name__ == "__main__":
    import doctest
    doctest.testmod()

The above should output TestResults(failed=0, attempted=4) if you have good code (it is good in this case.)

@samsara330

Your next challenge is to ensure that only valid input is given.

  • No negatives
  • Only integers