【问题标题】:counting odd numbers in a list python计算列表python中的奇数
【发布时间】:2021-04-14 14:52:14
【问题描述】:

这是我的家庭作业的一部分,我接近最终答案,但还没有。我需要编写一个计算列表中奇数的函数。

创建一个递归函数 count_odd(l),它的唯一参数是整数列表。该函数将返回奇数列表元素的数量,即不能被 2 整除。\

>>> print count_odd([])  
0  
>>> print count_odd([1, 3, 5])  
3  
>>> print count_odd([2, 4, 6])  
0  
>>> print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])  
8  

这是我目前所拥有的: #- 递归函数 count_odd -#

def count_odd(l):
    """returns a count of the odd integers in l.
    PRE: l is a list of integers.
    POST: l is unchanged."""
    count_odd=0

    while count_odd<len(l):
        if l[count_odd]%2==0:
            count_odd=count_odd
        else:
            l[count_odd]%2!=0
            count_odd=count_odd+1
    return count_odd

#- test harness  
print count_odd([])  
print count_odd([1, 3, 5])  
print count_odd([2, 4, 6])  
print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])  

你能帮忙解释一下我缺少什么吗?前两个测试工具工作正常,但我无法获得最后两个。谢谢!

【问题讨论】:

  • 你错过了递归。
  • 你能帮助解释我如何进行递归吗?我是 python 新手,我们的教授并没有很好地解释递归。
  • Recursion 不是 Python 特定的概念。一般来说,当你的函数体调用函数本身作为计算的一部分时,你就是在进行递归。
  • 另外,即使这个函数没有递归,逻辑也是有缺陷的。尝试使用[2,4,6] 参数一次一行地遍历它,看看是否能发现错误。

标签: python recursion


【解决方案1】:

由于这是作业,请考虑以下仅计算列表的伪代码:

function count (LIST)
    if LIST has more items
        // recursive case.
        // Add one for the current item we are counting,
        // and call count() again to process the *remaining* items.
        remaining = everything in LIST except the first item
        return 1 + count(remaining)
    else
        // base case -- what "ends" the recursion
        // If an item is removed each time, the list will eventually be empty.
        return 0

这与作业要求的内容非常相似,但需要将其转换为 Python,并且您必须制定正确的递归案例逻辑。

编码愉快。

【讨论】:

  • +1!这确实是问题的完整功能方法。不是说我会在 Python 中这样做,而是因为老师要求递归......
  • @justin 不应该有“while”和“counter”变量——计数是通过添加一些东西来完成的(在上面的例子中是“1”,但你可能需要让它依赖于 )到下一个递归调用的返回值 :-) 您可以对列表执行的唯一操作是“判断是否还有更多项目”(@987654322 @)、“第一次看”(list[0]——如果有的话)和“获取列表的其余部分”(list[1:]——第一项)。对于这个问题,对于 n != 0,不要使用list[n](例如,您不能对列表进行索引迭代)。
  • 嗯好的回到绘图板
  • @justin 如果你得到我在 Python 中发布的计数版本(这样count(l) == len(l),对于每个列表 l),它应该只是调整它的问题,所以它只计算 当前项目的某个条件为真。编码愉快。
  • 嗯好吧。会尽我所能。我是 python 的初学者,所以可能需要一些时间。学习一门新的编程语言非常令人沮丧。
【解决方案2】:
def count_odd(L):
    return (L[0]%2) + count_odd(L[1:]) if L else 0

【讨论】:

【解决方案3】:

切片好吗? 感觉对我来说不是递归的,但我想整个事情有点违反通常的习惯用法(即 - Python 中的这种递归):

def countOdd(l):
    if l == list(): return 0           # base case, empty list means we're done
    return l[0] % 2 + countOdd(l[1:])  # add 1 (or don't) depending on odd/even of element 0.  recurse on the rest

x%21 赔率,0 偶数。如果您对此感到不舒服或只是不理解,请使用以下内容代替上面的最后一行:

   thisElement = l[0]
   restOfList = l[1:]
   if thisElement % 2 == 0: currentElementOdd = 0
   else: currentElementOdd = 1
   return currentElementOdd + countOdd(restOfList)

PS - 这是相当递归的,如果你把它交给你,看看你的老师怎么说=P

>>> def countOdd(l):
...     return fold(lambda x,y: x+(y&1),l,0)
... 
>>> def fold(f,l,a):
...     if l == list(): return a
...     return fold(f,l[1:],f(a,l[0]))

【讨论】:

  • if l == list(): 应替换为 if not l:。可以提到内置的reduce() 函数(在你的代码中它被命名为fold())。
  • 其实整件事情都只是一条线:count_odd = lambda l: l[0]%2 + count_odd(l[1:]) if l else 0。现在这就是我所说的递归。 ;-)
  • @martineau:@Satoru.Logic 已经提供了该变体stackoverflow.com/questions/4230497/…
  • @J.F.塞巴斯蒂安:相同的逻辑,但有两行。
  • 我很了解reduce,但是如果我使用它,它看起来不会太递归吗?我选择了“fold”这个名字,所以我不会重新定义 reduce,因为我不想覆盖两个参数形式。
【解决方案4】:

所有先前的答案都将问题细分为大小为 1 和大小为 n-1 的子问题。一些人指出,递归堆栈可能很容易爆炸。此解决方案应将递归堆栈大小保持在 O(log n):

def count_odd(series):
    l = len(series) >> 1
    if l < 1:
        return series[0] & 1 if series else 0
    else:
        return count_odd(series[:l]) + count_odd(series[l:])

【讨论】:

    【解决方案5】:

    递归的目标是将问题分成更小的部分,并将解决方案应用于更小的部分。在这种情况下,我们可以检查列表的第一个数字 (l[0]) 是否为奇数,然后使用列表的其余部分 (l[1:]) 再次调用该函数(这是“递归”),添加我们当前的result 到递归的结果。

    【讨论】:

    • 嗯好吧,把它分成更小的部分是有意义的。现在我必须尝试将其合并到我的代码中。
    【解决方案6】:
    def count_odd(series):
        if not series:
            return 0
        else:
            left, right = series[0], series[1:]
            return count_odd(right) + (1 if (left & 1) else 0)
    

    【讨论】:

      【解决方案7】:

      尾递归

      def count_odd(integers):
          def iter_(lst, count):
              return iter_(rest(lst), count + is_odd(first(lst))) if lst else count
          return iter_(integers, 0)
      
      def is_odd(integer):
          """Whether the `integer` is odd."""
          return integer % 2 != 0 # or `return integer & 1`
      
      def first(lst):
          """Get the first element from the `lst` list.
      
          Return `None` if there are no elements.
          """
          return lst[0] if lst else None
      
      def rest(lst):
          """Return `lst` list without the first element."""
          return lst[1:]
      

      Python 中没有尾调用优化,所以上面的版本纯属教育性的。

      调用可以被可视化为:

      count_odd([1,2,3])    # returns
      iter_([1,2,3], 0)      # could be replaced by; depth=1
      iter_([2,3], 0 + is_odd(1)) if [1,2,3] else 0 # `bool([1,2,3])` is True in Python
      iter_([2,3], 0 + True) # `True == 1` in Python
      iter_([2,3], 1)        # depth=2
      iter_([3], 1 + is_odd(2)) if [2,3] else 1
      iter_([3], 1 + False)  # `False == 0` in Python
      iter_([3], 1)          # depth=3
      iter_([], 1 + is_odd(3)) if [3] else 1
      iter_([], 2)           # depth=4
      iter_(rest([]), 2 + is_odd(first([])) if [] else 2 # bool([]) is False in Python
      2 # the answer
      

      简单的蹦床

      为避免大型数组出现“超出最大递归深度”错误,递归函数中的所有尾调用都可以包装在lambda: 表达式中;和特殊的trampoline() 函数可以用来解开这样的表达式。它有效地将递归转换为对简单循环的迭代:

      import functools
      
      def trampoline(function):
          """Resolve delayed calls."""
          @functools.wraps(function)
          def wrapper(*args):
              f = function(*args)
              while callable(f):
                  f = f()
              return f
          return wrapper
      
      def iter_(lst, count):
          #NOTE: added `lambda:` before the tail call
          return (lambda:iter_(rest(lst), count+is_odd(first(lst)))) if lst else count
      
      @trampoline
      def count_odd(integers):
          return iter_(integers, 0)
      

      例子:

      count_odd([1,2,3])
      iter_([1,2,3], 0)         # returns callable
      lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
      iter_([2,3], 0+is_odd(1)) # returns callable
      lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
      iter_([3], 1+is_odd(2))   # returns callable
      lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
      iter_([], 1+is_odd(3))
      2                         # callable(2) is False
      

      【讨论】:

        【解决方案8】:

        我会这样写:

        def countOddNumbers(numbers): 
            sum = 0
            for num in numbers:
                if num%2!=0:
                    sum += numbers.count(num)
            return sum 
        

        【讨论】:

          【解决方案9】:

          不确定我是否收到了您的问题,但如上所述:

          def countOddNumbers(numbers): 
              count=0
              for i in numbers:
                  if i%2!=0:
                      count+=1
              return count
          

          【讨论】:

          • 任务是使用递归函数。该解决方案虽然看起来正确(我没有运行它),但不使用递归,因此无法回答问题。此外,如果您想要一个非递归解决方案,请考虑 reduce 内置函数。
          【解决方案10】:

          生成器可以在一行代码中快速给出结果:

          sum((x%2 for x in nums))
          

          【讨论】:

          • 您为现有答案增加了什么价值? OP 显然是以递归为目标之一进行学习,但您的答案根本没有解决 OP 的基本方面。
          猜你喜欢
          • 1970-01-01
          • 2018-09-04
          • 2016-03-04
          • 2021-11-13
          • 2017-03-08
          • 2020-02-19
          • 2020-08-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多