5

My assignment is:

"Write a function sumOfDigits that has one parameter of type string. The function should return the sum of the digits in the string. Do not treat multiple digit string as one number – “2014” should be treated as 4 different digits of 2, 0, 1, 4. The function should return 17 for the string “Today’s date is 09/01/2014”. You can assume the parameter is a string. No need to do any type validation."

Here's what I've got so far (with appropriate indentation):

def sumOfDigits (string1: str):

   summation=0

   for i in string1:
        summation=summation + int (i)

   return (summation) 

print (sumOfDigits ('543tf'))

I get the following error:

"Traceback (most recent call last):

  File "C:\Users\Andrew\Desktop\lab3.py", line 45, in <module>

    print (sumOfDigits ('543tf'))

  File "C:\Users\Andrew\Desktop\lab3.py", line 42, in sumOfDigits

    summation=summation + int (i)

ValueError: invalid literal for int() with base 10: 't'"

How do I solve this? Is it doing this because of the difficulties associated with adding an int and string/char?

AndyM3
  • 183
  • 1
  • 4
  • 13

5 Answers5

3

The problem is that int(x) fails unless x is a digit. The solution is to sum only the digits. For this purpose, python has the string method isdigit. For example:

>>> s = '543tf'
>>> sum(int(x) for x in s if x.isdigit())
12

And:

>>> s = "Today’s date is 09/01/2014"
>>> sum(int(x) for x in s if x.isdigit())
17

Python3

Unicode has added a large number of characters and python classifies some of them as digits even if int does not accept them. One such example is superscript 3: ³. To deal with this, python3 has introduced isdecimal and made it more discriminating than isdigit. Thus, in python3, one can use:

>>> s = "Today’s date is 09/01/2014 See footnote³"
>>> sum(int(x) for x in s if x.isdecimal())
17
John1024
  • 109,961
  • 14
  • 137
  • 171
  • You want `isdecimal`; `isdigit` has false positives like `""`. This is exactly why a `try`...`catch` is preferred. – Veedrac Oct 11 '14 at 13:51
3

You can do type-checking like what the other people have mentioned, or just pass the exception in the following manner (with minimal modification to your code so it is easy to see how it works):

def sumOfDigits (string1):
   summation=0
   for i in string1:
        try:
            summation = summation + int(i)
        except:
            pass

   return (summation) 

This is one of the philosophies of Python that says that you assume that the input is correct and only catch the exceptions and handle them separately. You might even want to explicitely check for the ValueError rather than catching all exceptions. Bit the details depend upon you.

ssm
  • 5,277
  • 1
  • 24
  • 42
1

You can't cast a char to an int and expect it to return 0 if it's not an int and its numerical value otherwise. You need to split up the string, check if the characters represent integers, and add those up. Like this:

def sumdigits(mystring):
    summation = 0
    for letter in list(mystring):
        if letter.isdigit():
            summation += int(letter)
    return summation
Newb
  • 2,810
  • 3
  • 21
  • 35
1

This will do the trick:

sum(int(d) for d in '09/01/2014' if d.isdigit())

but I don't recommend handing it in without being able to explain how it works :-)

You could also try figuring out how

sum(map(int,filter(str.isdigit,'09/01/2014')))

works.

Your attempt is not failing 'because of difficulties of adding ints to char' (at least not directly), it's actually failing before that: when you try to convert something that doesn't look remotely like a number ('t') into an int. Which is what the error message is trying to tell you (right at the very bottom: 'ValueError etc.'). How do you solve it? You remove the stuff that can't be converted to int before attempting the conversion. The two code samples I gave you contain hints suggesting two different ways you might do it.

jacg
  • 2,040
  • 1
  • 14
  • 27
1

There are many ways to skin this cat.

One is to use a regex to find the single digits:

>>> import re
>>> re.findall(r'(\d)', '543tf')
['5', '4', '3']

Put that inside of map and convert to ints:

>>> map(int, re.findall(r'(\d)', '543tf'))
[5, 4, 3]

Put that into sum to sum the list:

>>> sum(map(int, re.findall(r'(\d)', '543tf')))
12
dawg
  • 98,345
  • 23
  • 131
  • 206