【问题标题】:Finding the average of a string while going backwards向后查找字符串的平均值
【发布时间】:2017-11-23 02:52:52
【问题描述】:

我需要定义一个函数,它接收一个字符串(可能包含数字、字母和/或特殊符号)并返回一个浮点数,其中包含考虑到字符串中所有数字从字符串中的最后一个位置开始计算的平均值,并且考虑所有数字(向后),直到找到一个字母或直到到达字符串的开头(如果它是数字,则包括字符串中的第一个字符以进行计算)。如果字符串中没有数字,或者如果在找到第一个数字之前找到了一个字母,则该函数应返回值 0.0。

例如,avgBackw("-1---2--A--3--4--") 应该返回 3.5,因为 4 和 3 的平均值是 3.5。

As an example, the following code fragment:

value = avgBackw("-1---2--A--3--4--")
print(value)

should produce the output:

3.5

这是我到目前为止最远的地方..我不知道从这里去哪里..

def avgBackw(lst): 
  rv = []  
  for n in lst[::-1]: 
    try:
        rv.append(int(lst))
    except:
        return len(rv)
return len(rv)

【问题讨论】:

  • 因此,如果您想获得平均值,您需要跟踪总和以及您遇到的位数。您可以使用.isdigit().isalpha() 来检查字符是数字还是字母。当你遇到一个数字时,你将它的值记录在 sum 中,当你遇到一个字母时,你就跳出循环。一旦你退出循环,你就会返回平均值,你可以使用你的总和和位数来计算。一定要考虑没有数字的情况,否则你会被零除。
  • 向后求平均值的目的是什么,是特殊情况,例如 avgBackw("-1---2--A--3--04--") 假设产生 (40 +3)/2 = 21.5 或仅 3.5
  • 如果我们有连续的数字比如--A-1--45--4怎么办

标签: python loops while-loop average


【解决方案1】:

您可以使用regex 来解决您的问题,例如以下示例:(请参阅 cmets 以了解幕后情况):

import re 

def find_sep(a):
    '''Find the separator which is anything except numbers and "-" '''
    # é, è, æ, etc ... are not a valid separators.
    # Otherwise, add them to the next line in the regex rule
    sep = re.findall(r'[a-zA-Z]', a[::-1])
    if sep:
        # Reverse the string
        # And take the first part of the string if we find a separator
        return a[::-1].split(sep[0])[0]
    else:
        # Return the string reversed
        return a[::-1]


def average_backwards(a):
    '''Reverse the string and calculate the average'''
    # Find the seperator if exists and return an inversed string with numbers if they exists
    b = find_sep(a)
    # Find all the numbers
    nums = re.findall(r'(\d+)', b[::-1])
    if nums:
        avg = round(sum(map(int, nums))/len(nums), 2)
        return avg
    return 0.0


# Test

nums = ["-1---2--b--3--04--", "-1---2--e--3--4--", "-1---2--A--3--A--", "-1---2--A--3----", 
        "-A---A--A--A--1--", "-A---A--A--+--1--", "-A---A--A--A--A--", "-A---2--A--A--A--", 
        "-5---4--3--2--1--", "-5-Z--4--3--2--1--", "-A---4--3------", "-A---4--c--2--1--", 
        "----4--A--2--1--", "-A---4--A--2--1--", "-5-Z--4-+3--2--1-"]


for num in nums:
    print('{0} -> avg: {1}'.format(num, average_backwards(num)))

输出:

-1---2--b--3--04-- => 3.5
-1---2--e--3--4-- => 3.5
-1---2--A--3--A-- => 0.0
-1---2--A--3---- => 3.0
-A---A--A--A--1-- => 1.0
-A---A--A--+--1-- => 1.0
-A---A--A--A--A-- => 0.0
-A---2--A--A--A-- => 0.0
-5---4--3--2--1-- => 3.0
-5-Z--4--3--2--1-- => 2.5
-A---4--3------ => 3.5
-A---4--c--2--1-- => 1.5
----4--A--2--1-- => 1.5
-A---4--A--2--1-- => 1.5
-5-Z--4-+3--2--1- => 2.5

【讨论】:

  • 你能解释一下-A---4--c--2--1-- -> avg: 2.33 鉴于OP 对问题的描述吗?我看不出它与-A---4--A--2--1-- -> avg: 1.5 有何不同。谢谢。
  • 感谢@cdlane 指出此错误。我只需要在find_sep 中反转a。请参阅最后的编辑。背后的想法是找到反转字符串中的第一个字母,然后将字符串除以该字母,然后找到所有数字,将它们相加并求平均值。
  • OP 很清楚一个字母(或字符串结尾)会停止处理,但您的代码会在其他标点符号上停止,例如-5-Z--4-+3--2--1- -> avg: 2.0
  • 我明白了。所以,我需要修改 find_sep 下的正则表达式。我正在更新我的答案。谢谢@cdlane
【解决方案2】:

我从不错过将 itertools.groupby 用于解决问题的机会:

from itertools import groupby

def avgBackw(string):
    digits = list()

    for key, group in groupby(string[::-1], lambda c: c.isalnum() + c.isdigit()):

        if key == 1:  # we hit one or more letters
            break

        if key == 2: # we hit one or more digits
            digits += group

    return sum(map(int, digits)) / len(digits) if digits else 0

【讨论】:

    【解决方案3】:

    使用isalpha()isdigit()

    def avgBack(string):
        sum, count =  0.0, 0
        for s in string[::-1]:
            if s.isalpha():
                break
            if s.isdigit():
                sum += int(s)
                count+=1
        return float(sum/count) if count else 0
    

    【讨论】:

    • 我看不出float(sum/count) 的目的——我本来期望类似:sum / float(count) 假设您正在尝试兼容 Python 2 和 Python 3。
    • 此解决方案假定必须有一个字母终止符,所以如果没有,例如-5---4--3--2--1--,它返回零而不是平均值。一个简单的修复。
    • @cdlane 感谢您的建议,我已经更新了我的解决方案。
    【解决方案4】:

    你需要做的是:

    1.去除除数字和字母以外的所有字符

    2.反转剥离列表

    3.检查基本情况

    4.在找到一个字符之前计算所有数字的平均值

    以下是蛮力方法的样子(没有有用的库函数):

    def average_back(string):
        # sum count for average
        count = 0
        sums = 0.0
    
        # strip the string except for the digits and letters
        stripped = []
        for char in string:
            if char.isdigit() or char.isalpha():
                stripped.append(char)
    
        # reverse the string
        reverse = stripped[::-1]
    
        # if list is empty, of no digits are found, or the first letter is a letter
        if not reverse or not has_number(reverse) or reverse[0].isalpha():
            return sums
    
        # loop until character is found
        for char in reverse:
            if char.isalpha():
                break
            else:
                sums += float(char)
                count += 1
    
        # return average
        return sums / count
    
    def has_number(string):
        for char in string:
            if (char.isdigit()):
                return True
    
        return False
    

    使用map()any()itertools.takewhile()str.join()等高阶函数的另一个更简洁(可以改进)的实现:

    from itertools import takewhile
    
    def average_back2(string):
    
        # strip the string except for the digits and letters
        stripped = "".join(x for x in string if x.isalpha() or x.isdigit())
    
        # reverse the string
        reverse = stripped[::-1]
    
        # if list is empty, of no digits are found, or the first letter is a letter
        if not reverse or not any(x.isdigit() for x in reverse) or reverse[0].isalpha():
            return 0.0
    
        # concatenate numbers until non-digit is found
        valid_numbers = "".join(takewhile(lambda x : not x.isalpha(), reverse))
    
        # convert string to list of integers
        numbers = list(map(int, valid_numbers))
    
        # return sum
        return sum(numbers) / len(numbers)
    

    其工作原理如下:

    >>> average_back("-1---2--A--3--4--")
    3.5
    >>> average_back2("-1---2--A--3--4--")
    3.5
    >>> average_back("-1---2--A--3--A--")
    0.0
    >>> average_back2("-1---2--A--3--A--")
    0.0
    >>> average_back("-A---A--A--A--1--")
    1.0
    >>> average_back2("-A---A--A--A--1--")
    1.0
    >>> average_back("-A---A--A--A--A--")
    0.0
    >>> average_back2("-A---A--A--A--A--")
    0.0
    >>> average_back("-5---4--3--2--1--")
    3.0
    >>> average_back2("-5---4--3--2--1--")
    3.0
    >>> average_back("-A---4--3--2--1--")
    2.5
    >>> average_back2("-A---4--3--2--1--")
    2.5
    >>> average_back("-A---4--A--2--1--")
    1.5
    >>> average_back2("-A---4--A--2--1--")
    

    【讨论】:

      猜你喜欢
      • 2014-02-24
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2018-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      相关资源
      最近更新 更多