【问题标题】:Return second smallest number in a nested list using recursion使用递归返回嵌套列表中的第二小数字
【发布时间】:2017-07-16 20:06:42
【问题描述】:

我必须使用递归返回 Python 列表中的第二小数,并且没有循环。我所做的是创建了一个辅助函数,它返回列表中(最小的,第二小的)值的元组,然后我只需在我的 second_smallest 函数中使用 tuple[1]

def s_smallest(L):

    if(len(L) == 2):
        if (L[0] >= L[1]):
            return (L[1],L[0])
        else:
            return (L[0],L[1])
    else:
        first_smallest,second_smallest = s_smallest(L[1:])

        if L[0] >= first_smallest and L[0] <= second_smallest:
            return (first_smallest, L[0])

        elif L[0] <= first_smallest:
            return (L[0], first_smallest)

        else:
            return (first_smallest, second_smallest)

这可行,但现在我需要处理嵌套列表,所以s_smallest([1,2,[3,0]]) 应该返回(0,1)。我试过这样做:

if isinstance(L[0],list):
    first_smallest,second_smallest = s_smallest(L[0])
else:
    first_smallest,second_smallest = s_smallest(L[1:])

如果它是一个列表,则获取第一个最小值和第二个最小值,但我收到一条错误消息builtins.TypeError: unorderable types: int() &gt;= list()。如何解决此问题以处理嵌套列表?

【问题讨论】:

  • 错误的明显来源是您没有完成该代码的集成。如果 L[0] 是一个列表,那么您必须对其进行递归,然后继续使用 L[1] 进行处理。你不能再使用 L[0],因为它是一个列表,而不是一个整数。不过,你走在正确的轨道上。尝试类似l0,l1 = s_smallest(L[0]); m0,m1=s_smallest(L[1:]); 然后合并 l0,l1,m0,m1
  • 另外,请注意在len(L)==2 时可能仍然涉及一两个列表的可能性(如您的示例中所示)。您可能应该一直递归,并处理 None 或 len=1 案例

标签: python algorithm list recursion


【解决方案1】:

我可能建议将列表取消嵌套和最小减少分成两个单独的、定义明确的任务

  • deepReduce 将使用指定的归约函数归约列表列表
  • deepMin 使用 min 执行 deepReduce
import math # used for math.inf

def min (x,y):
  return x if x < y else y

def deepReduce (f, y, xs):
  if not xs:
    return y
  elif isinstance(xs[0], list):
    return deepReduce(f, deepReduce(f, y, xs[0]), xs[1:])
  else:
    return deepReduce(f, f(y, xs[0]), xs[1:])

def deepMin (xs):
  return deepReduce (min, math.inf, xs)


data = [1,2,[7,[6,1,3,[0,4,3]],3,4],2,1]
print(deepMin(data))
# 0

哦,但你说你想要第二个最小的数字。让我们稍微修改一下代码。当然我一直都知道,但是两次回答这个问题可以让我展示这个特定实现的多功能性 - bold

的变化
def min2 (xs, y):
  # x1 is the smallest, x2 is second smallest
  x1, x2 = xs
  if (y < x1) and (y < x2):
    return (y, x2)
  elif y < x2:
    return (x1, y)
  else:
    return (x1, x2)

def deepMin2 (xs):
  # notice we change to use tuple of math.inf now
  x1, x2 = deepReduce (min2, (math.inf, math.inf), xs)
  return x2

data = [1,2,[7,[6,1,3,[0,4,3]],3,4],2,1]
print(deepMin2(data))
# 1

我应该指出,我们根本不需要接触deepReduce,这就是重点——我们应该能够对嵌套列表进行任意深度操作,而无需将这种行为静态编码到我们的函数中.

现在你可以编写任何你想要的深度reducer并使用deepReduce调用它

【讨论】:

  • 这是一个很好的解决方案,但是否可以不导入任何内容?
  • 只使用基本的python?
  • math 模块包含在 python 中...但是如果您必须引入类似的任意限制,请将 math.inf 替换为“非常大”的数字。
  • 另一种选择是将math.inf 替换为None 并在min2 中写入另一个条件以在进行&lt; 比较之前检查None
【解决方案2】:

完整解决方案

只使用functools.reduce,没有循环,来处理任意嵌套的列表:

import functools

def helper(acc, x):
    if type(x) is list:
        return functools.reduce(lambda acc, x: helper(acc, x), x, acc)
    else:
        if x < acc[0]:
            return (x, acc[0])
        elif x < acc[1]:
            return (acc[0], x)
        else:
            return (acc[0], acc[1])

def second_smallest(l):
    if len(l) < 2:
        return None
    else:
        if l[0] <= l[1]:
            return functools.reduce(lambda acc, x: helper(acc, x), l[2:], (l[0], l[1]))
        else:
            return functools.reduce(lambda acc, x: helper(acc, x), l[2:], (l[1], l[0]))

>>> second_smallest([1,2,[0,3,[-1,-2]]])
(-2, -1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多