简体   繁体   English

从数字和字母列表中删除字母

[英]Removing letters from a list of both numbers and letters

In a function I'm trying to write, the user enters a bunch of numbers eg "648392". 在我正在尝试编写的函数中,用户输入一组数字,例如“648392”。 I turn this string into a list like this: ['6', '4', '8', '3', '9', '2']. 我把这个字符串变成这样的列表:['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". 例如,用户输入“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! 我无法检查元素是否是带有isDigit的数字,因为元素显然必须首先是整数,并且我无法将列表中的元素转换为整数,因为有些元素是字母...我我确定有一个简单的解决方案,但我在python中非常糟糕,所以任何帮助都将非常感激!

You can use str.translate to filter out letters: 您可以使用str.translate过滤掉字母:

>>> 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: 使用str.joinstr.isdigit和list comprehension:

>>> ''.join([c for c in strs if c.isdigit()])
'64832'

or this as you want the sum of digits: 或者这就像你想要的数字之sum

sum(int(c) for c in strs if c.isdigit())

Timing comparisons: 时间比较:

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. 您可以使用过滤filter函数或理解来过滤任何可迭代(包括字符串)中的内容。 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: 因此,要获取所有数字的总和,跳过字母,只需将其中任何一个传递给sum函数:

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 我无法检查元素是否是带有isDigit的数字,因为元素显然必须首先是整数,并且我无法将列表中的元素转换为整数

First, it's isdigit , not isDigit . 首先,它是isdigit ,而不是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. 其次, isdigit是一个关于字符串而不是整数的方法,所以你认为你不能在字符串上调用它是错误的。 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 . 在Python中, 要求宽恕通常比权限更容易 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. 我们可以尝试将它转换为int,然后处理可能的失败,而不是弄清楚我们是否可以将每个字母转换为int,然后再进行转换。 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))

You can do this with a comprehension: 你可以通过理解来做到这一点:

>>> s = "6483A2"
>>> [int(c) for c in s if c.isdigit()]
[6, 4, 8, 3, 2]
>>> sum(int(c) for c in s if c.isdigit())
23

This approach is good if you want to go straight from the mixed string to a list of only the integers, which is presumably your goal. 如果你想直接从混合字符串到只有整数的列表,这种方法很好,这可能是你的目标。

You can use a generator expression and put it in the sum . 您可以使用生成器表达式并将其放入sum

>>> import string
>>> s
'6483A2'
>>> sum(int(x) for x in list(s) if x in string.digits)
23

If no other module want to import, use isdigit : 如果没有其他模块要导入,请使用isdigit

sum(int(x) for x in list(s) if x.isdigit())
>>> a = "hello123987io"
>>> b = "khj7djksh787"
>>> sum([int(letter) for letter in b if letter.isdigit()])
29
>>> sum([int(letter) for letter in a if letter.isdigit()])
30

>>> def getInputAndSum(userInput):
...     """ returns a tuple with the input string and its sum """
...     return userInput, sum([int(letter) for letter in userInput if letter.isdigit()])
... 
>>> getInputAndSum("Th1s1550mesum")
('Th1s1550mesum', 12)

Just to contribute a little, if you want the aggregated sum you can do it all like this: 只是贡献一点,如果你想要汇总总和,你可以这样做:

x = "6483A2"
sum(map(int, filter(str.isdigit, x)))
>>>23

If you need the list of integers only for other purposes or other kind of sum then just leave it in map : 如果您只需要用于其他目的的整数列表或其他类型的sum ,请将其保留在map

map(int, filter(str.isdigit, x))
>>>[6, 4, 8, 3, 2]

Note: About the string.letters approach. 注意:关于string.letters方法。 letters is locale dependent so this: letters依赖于locale因此:

import locale, string
locale.setlocale(locale.LC_ALL, 'es_ES') # or 'esp_esp' if you're on Windows
string.letters
>>> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzŠŚŽšśžźŞµşŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőöřůúűüýţ˙"

Although I would recommend regex for this case as suggested above :) 虽然如上所述,我会为这种情况推荐regex :)

Nice to collaborate :D 很高兴合作:D

While it's certainly true you can filter out letters in various ways, it's probably more Pythonic to let the interpreter decides what can be interpreted as a digit and what cannot. 虽然你可以用各种方式过滤掉字母,但是让译员决定什么可以被解释为数字和什么不可以。 So even though it's not a one-liner, you may prefer this approach: 所以即使它不是单行,你可能更喜欢这种方法:

aninput = "648392A0&sle4"
def discard_non_ints(itbl, rdx=10):
  for d in itbl:
    try:
      yield(int(d, rdx))
    except ValueError:
      pass

sum(discard_non_ints(aninput))
36

What's particularly nice about this approach is it gives you the flexibility to include non-decimal digits. 这种方法特别好用的是它可以灵活地包含非十进制数字。 Want to sum all the hexidecimal digits? 想要求所有十六进制数字?

sum(discard_non_ints('deadbeforenoon', 16))
104

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM