In a function I'm trying to write, the user enters a bunch of numbers e.g. "648392". I turn this string into a list like this: ['6', '4', '8', '3', '9', '2'].
I wanted to be able to do sums with these numbers so I was turning the numbers in the list into integers rather than strings. This all worked fine, however I also wanted the user to be able to enter letters, and then I would just remove them from the list - and this is where I'm stuck. For example a user entering "6483A2".
I can't check to see if an element is a digit with isDigit because the elements apparently have to be integers first, and I can't convert the elements in the list to integers because some of the elements are letters... I'm sure there's a simple solution but I am pretty terrible at python, so any help would be much appreciated!
You can use str.translate
to filter out letters:
>>> from string import letters
>>> strs = "6483A2"
>>> strs.translate(None, letters)
'64832'
There's no need to convert a string to a list, you can iterate over the string itself.
Using str.join
, str.isdigit
and list comprehension:
>>> ''.join([c for c in strs if c.isdigit()])
'64832'
or this as you want the sum
of digits:
sum(int(c) for c in strs if c.isdigit())
Tiny string:
>>> strs = "6483A2"
>>> %timeit sum(int(c) for c in strs.translate(None, letters))
100000 loops, best of 3: 9.19 us per loop
>>> %timeit sum(int(c) for c in strs if c.isdigit())
100000 loops, best of 3: 10.1 us per loop
Large string:
>>> strs = "6483A2"*1000
>>> %timeit sum(int(c) for c in strs.translate(None, letters))
100 loops, best of 3: 5.47 ms per loop
>>> %timeit sum(int(c) for c in strs if c.isdigit())
100 loops, best of 3: 8.54 ms per loop
Worst case, all letters:
>>> strs = "A"*100
>>> %timeit sum(int(c) for c in strs.translate(None, letters))
100000 loops, best of 3: 2.53 us per loop
>>> %timeit sum(int(c) for c in strs if c.isdigit())
10000 loops, best of 3: 24.8 us per loop
>>> strs = "A"*1000
>>> %timeit sum(int(c) for c in strs.translate(None, letters))
100000 loops, best of 3: 7.34 us per loop
>>> %timeit sum(int(c) for c in strs if c.isdigit())
1000 loops, best of 3: 210 us per loop
You can filter things out of any iterable (including a string) with the filter
function, or a comprehension. For example, either of these:
digits = filter(str.isdigit, input_string)
digits = (character for character in input_string if character.isdigit())
… will give you an iterable full of digits. If you want to convert each one to a number, either of these will do it:
numbers = map(int, filter(str.isdigit, input_string))
numbers = (int(character) for character in input_string if character.isdigit())
So, to get the sum of all the digits, skipping the letters, just pass either of those to the sum
function:
total = sum(map(int, filter(str.isdigit, input_string)))
total = sum(int(character) for character in input_string if character.isdigit())
From your last paragraph:
I can't check to see if an element is a digit with isDigit because the elements apparently have to be integers first, and I can't convert the elements in the list to integers
First, it's isdigit
, not isDigit
. Second, isdigit
is a method on strings, not integers, so you're wrong in thinking that you can't call it on the strings. In fact, you must call it on the strings before converting them to integers.
But this does bring up another option. In Python, it's often Easier to Ask Forgiveness than Permission. Instead of figuring out whether we can convert each letter to an int, and then doing it, we can just try to convert it to an int, and then deal with the possible failure. For example:
def get_numbers(input_string):
for character in input_string:
try:
yield int(character)
except TypeError:
pass
Now, it's just:
total = sum(get_numbers(input_string))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With