【问题标题】:Python Recursion vs IterationPython 递归与迭代
【发布时间】:2016-09-12 18:01:52
【问题描述】:

我在我的代码中找不到错误。它在我的 cmd 上运行得很好,但不会通过实验室平台测试。问题来了:

您需要设计一个迭代和递归函数,分别称为replicate_iter 和replicate_recur,它们将接收两个参数:times 是重复的次数,data 是要重复的数字或字符串。

该函数应返回一个包含重复数据参数的数组。例如,replicate_recur(3, 5)replicate_iter(3,5) 应该返回 [5,5,5]。如果 times 参数为负数或零,则返回一个空数组。如果参数无效,请提出ValueError。"

现在这是我的代码:

my_list1 = []
my_list2 = []
   def replicate_iter(times,data):
      try:
        if type(data) != int and type(data) != str:
          raise ValueError('Invalid Argument')
        times += 0
          if times > 0:
            x = 0
            while x < times:
            my_list2.append(data)
            x = x+1
           return my_list2
         else:
          return []
    except (ValueError,AttributeError,TypeError):
        raise ValueError('Invalid Argument')

def replicate_recur(times,data):
    try:
        if type(data) != int and type(data) != str:
          raise ValueError('Invalid Argument')
        times += 0
        if times <= 0:
          return my_list1
        else:
          my_list1.append(data)
          return replicate_recur(times-1,data)
    except(AttributeError,TypeError):
        raise ValueError('Invalid Argument')

【问题讨论】:

  • 请为该站点更好地格式化您的代码。如果你用 4 个字符空间缩进你的句子(通常是一个制表符),它会更好地显示一个代码块。
  • 为什么要使用全局变量?
  • 不知道这是否是你失败的原因,但这条线是错误的:type(data) != int and type(data) != str:
  • 我正在使用全局变量,因为我不希望每次递归都改变值
  • 不要打扰类型检查。任何此类异常都表明该函数被错误调用或代码中存在错误;任一种情况都可以通过让代码自然失败来有效地发出信号。

标签: python recursion iteration


【解决方案1】:

这行得通!

def replicate_iter(times, data):
    if((not isinstance(times, int)) or (not isinstance(data, (int, float, long, complex, str)))):
            raise ValueError("Invalid arguments")
    elif(times <= 0):
            return []
    else:
            array = []
            for x in range(times):
                    array.append(data)
            return array


def replicate_recur(times, data):
    if((not isinstance(times, int)) or (not isinstance(data, (int, float, long, complex, str)))):
            raise ValueError("Invalid arguments")
    elif(times <= 0):
            return []
    else:
            return ([data] + replicate_recur((times - 1), data))        

【讨论】:

  • 您可以使用数字numbers.Number 的抽象基类,而不是列出数字类型的所有实现,因为long 已不复存在,这在python 3 中有失败的风险
  • 迭代版本中times &lt;= 0 的特殊情况不是必需的。对于任何小于 1 的值,for 循环的主体将永远不会运行,因为范围将为空,因此 array 将保持为空。
【解决方案2】:
def replicate(c,times):
    return [c]*times

def replicate2(c,times):
    return [c for i in range(times)]

def replicate3(c,times):
    result = []
    for i in range(times): result.append(c)
    return result

def replicate4(c,times):
    return [c] + (replicate4(c,times-1) if times > 0 else [])

【讨论】:

    【解决方案3】:

    我认为你的代码比其他人说的更接近正确——你只需要重新排列一些元素:

    def replicate_iter(times, data):
        if type(data) != int and type(data) != str:
            raise TypeError('Invalid Argument')
    
        try:
            my_list = []
    
            if times > 0:
                for _ in range(times):
                    my_list.append(data)
    
            return my_list
    
        except (ValueError, TypeError):
            raise ValueError('Invalid Argument') from None
    
    def replicate_recur(times, data):
        if type(data) != int and type(data) != str:
            raise TypeError('Invalid Argument')
    
        try:
            my_list = []
    
            if times > 0:
                my_list.append(data)
                my_list.extend(replicate_recur(times - 1, data))
    
            return my_list
    
        except (ValueError, TypeError):
            raise ValueError('Invalid Argument') from None
    

    我同意错误处理有点复杂,但这正是规范所要求的。尽管对 times 参数进行了具体说明,但规范对于如果 data 不是可接受的类型之一会生成哪个错误的规范是模棱两可的,但 TypeError 似乎是有道理的。

    【讨论】:

      【解决方案4】:

      对于递归版本,我推荐tail recursion,就像您已经在做的那样,其他示例即使最简单地使用列表连接(+),它也会生成一个包含每个元素副本的新列表,这太多了当您可以传递单个列表时,您可以像使用迭代版本一样向其中添加元素,这会浪费时间和空间

      这是一个例子

      def replicate_recur(times, data, result=None):
          if result is None:
              result = []
          if times <= 0 :
              return result
          else:
              result.append(data)
              return replicate_recur(times-1,data,result)
      

      此外,您可以通过使用辅助功能避免一遍又一遍地重复相同的检查

      def replicate_recur_aux(times, data, result):
          if times <= 0 :
              return result
          else:
              result.append(data)
              return replicate_recur_aux(times-1,data,result)  
      
      def replicate_recur(times, data):
          if not isinstance(data, int) and not isinstance(data, str):
              raise ValueError('Invalid Argument')
          return replicate_recur_aux(times,data,[])
      

      这样,主要功能只需一次完成所有需要完成的检查和所有必要的设置,因此辅助功能可以完成其工作,而无需担心或对同一件事进行不必要的检查。

      对于迭代版本,任何其他示例都很好,但也许你的老师想要这样的东西

      def replicate_iter(times, data):
          if not isinstance(data, int) and not isinstance(data, str):
              raise ValueError('Invalid Argument')
          result = []
          if times <=0:
              return result
          for i in range(times):
              result.append(data)
          return result
      

      现在注意到两个版本之间的相似之处,您可以轻松地将一个转换为另一个

      【讨论】:

        【解决方案5】:

        我认为迭代版本很简单,其他人也提供了很好的答案。至于递归,我总是想看看我是否能想出一个分而治之的策略,而不是一步一步地减少问题,以避免爆出堆栈。以下是这样做的:

        def replicate_recur(times, data):
            def f(n, value):
                if n < 1:
                    return [] 
                result = f(n // 2, value) * 2
                if n % 2 > 0:
                    result += [value] 
                return result
        
            if not isinstance(data, int) and not isinstance(data, str):
                raise ValueError('Must be int or str')
            return f(times, data)
        

        这使用内部递归函数f() 来避免重复对data 的类型检查。递归构造一个大小减半的列表,然后将其加倍(如果当前的n 为偶数)或将其加倍并再添加一次data(如果当前的n 为奇数)。

        试试吧,你会喜欢的!

        【讨论】:

          【解决方案6】:

          两者的基本实现(虽然说实话它们不是好的 Python)是:

          def replicate_iter(times, data):
              result = []
              for _ in range(times):  # xrange in Python2
                  result.append(data)
              return result
          
          
          def replicate_recur(times, data):
              if times <= 0:
                  return []
              return [data] + replicate_recur(times - 1, data)
          
          
          assert replicate_iter(3, 5) == [5, 5, 5]
          assert replicate_recur(3, 5) == [5, 5, 5]
          assert replicate_iter(4, "abc") == ["abc", "abc", "abc", "abc"]
          assert replicate_recur(4, "abc") == ["abc", "abc", "abc", "abc"]
          

          它们简单明了,显示了两种方法之间的基本区别。

          Pythonic 代码要么使用序列相乘,要么使用列表推导:

          result = [data for _ in range(times)]
          result = [data] * times
          

          在任何生产代码中,递归都不会真正用于此任务。

          【讨论】:

            【解决方案7】:

            我试过这个,它对那个测试有效!

            def replicate_iter(times,data):
                Array = []
                if type(times) != int or not isinstance(data, (int, float, complex, str)):
                    raise ValueError ('Invalid Value')
                elif times < 0:
                    return []
                else:
                    for x in range (times):
                        Array.append(data)
                    return Array
            
            
            def replicate_recur(times,data):
                Array = []
                if type(times) != int or not isinstance(data, (int, float, complex, str)):
                    raise ValueError ('Invalid Value')
                elif times <= 0:
                    return []
                else:
                   Array = replicate_recur(times-1,data)
                   Array.append(data)
                return Array
            

            【讨论】:

              【解决方案8】:
              def replicate_iter(times, data):
                  if not isinstance(data, int) and not isinstance(data, str):
                      raise ValueError('Must be int or str')
                  if times <= 0:
                      return []
                  return [data for _ in range(times)]
              
              def replicate_recur(times, data):
                  if not isinstance(data, int) and not isinstance(data, str):
                      raise ValueError('Must be int or str')
                  if times <= 0:
                      return []
                  return [data] + replicate_recur(times-1, data)
              

              输出

              >>> replicate_iter(3, 5)
              [5, 5, 5]
              
              >>> replicate_recur(3, 5)
              [5, 5, 5]
              

              边缘案例

              >>> replicate_iter(0, 5)
              []
              
              >>> replicate_iter(3, list())
              Traceback (most recent call last):
                File "<pyshell#2>", line 1, in <module>
                  replicate_iter(3, list())
                File "C:/temp/temp.py", line 3, in replicate_iter
                  raise ValueError('Must be int or str')
              ValueError: Must be int or str
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-04-26
                • 2018-08-16
                • 2012-08-29
                • 2021-05-26
                • 2015-07-18
                • 2015-02-06
                • 2011-02-08
                • 1970-01-01
                相关资源
                最近更新 更多