2017-02-26 104 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)