2017-02-26 70 views
6

返回嵌套表第二小的数字我已经在使用递归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() >= list()。我如何解决这个问题来处理嵌套列表?

+0

的你的错误的明显来源是你没有完成整合代码。如果L [0]是一个列表,那么你必须对它进行递归,然后继续用L [1]处理。您不能再使用L [0],因为它是一个列表,而不是一个整数*。不过,你正走在正确的轨道上。尝试像'l0,l1 = s_smallest(L [0]); m0,m1 = s_smallest(L [1:]);'然后合并l0,l1,m0,m1 –

+0

另外,要小心可能性(如你的例子),当len(L)== 2'成为一个或两个涉及的名单。你可能应该一路下调,并处理'无'或什么的len = 1 case –

回答

5

我可能会建议分离列表unnesting和最小还原成两个独立的,定义明确的任务

  • deepReduce将减少使用指定的还原作用
  • deepMin列表的列表的deepReduce使用min执行
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 

哦,但你说你想要的最小号码。让我们稍微修改一下这些代码。当然,我知道,一直以来,但在回答这个问题两次让我来证明该具体实施方式的多功能性 - 在变化大胆

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在所有这些都是重点 - 我们应该可以对嵌套列表进行任意深度的操作,而不必将该行为静态编码到我们的函数中。

现在你可以写任何你想要的深减速,并与deepReduce

+0

这是一个很好的解决方案,但它可以做到不输入任何东西? –

+0

只需使用基本的python? –

+0

那么'数学'模块包含在python中......但是如果你必须引入这样的任意限制,那么用一个“非常大”的数字来替换'math.inf'。 – naomik

0

完整的解决方案

调用它只是用普通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)