在Python3中使用递归查找列表列表中的第二小int
我想在可能存在空列表的列表中找到第二个最小的int。我在平坦的台阶上卡住了 我的想法在Python3中使用递归查找列表列表中的第二小int,python,recursion,Python,Recursion,我想在可能存在空列表的列表中找到第二个最小的int。我在平坦的台阶上卡住了 我的想法 未排序的列表,例如[1,3,2]、[4]、[12,12]、[12]、[12]、[12]、[12]、[12]、[12]、[4]、[4]、[4]、[12]、[12]、[12]、[12]、[12]、[12]、[12]、[12]、[4 结巴!!!!!!使用纯递归将列表展平。我在递归步骤的第一部分中尝试过这样做。上面的例子变成[1,3,2,4],[12,12,12] 查找第二个最小整数(已完成) 这是密码 def fin
def find(abc):
#base case
if len(abc) == 2:
if isinstance(abc[0], list) and isinstance(abc[1], list):
re = find(abc[0] + abc[1])
elif isinstance(abc[1], list):
re = find(abc[:1] + abc[1])
elif isinstance(abc[0], list):
first = find(abc[0] + abc[1:])
else:
if abc[0] > abc[1]:
re = (abc[0], abc[1])
else:
re = (abc[1], abc[0])
# recursive step
else:
#i think this part has problem
# flatten the list
if isinstance(abc[0], list):
re = find(abc[0] + abc[1:])
# if this element is interger
else:
current = abc[0]
second, first = find(abc[1:])
if (second < current):
re = (second, first)
elif (current > first) and (second >= current):
re = (current, first)
else:
re = (first, current)
return re
e.g find([[[]], [12, 12], [[12], []], [[]]]) -> (12, 12)
find([1, [2, 3], [[]], [4]]) -> (2, 1)
def find(abc):
#基本情况
如果len(abc)==2:
如果isinstance(abc[0],列表)和isinstance(abc[1],列表):
re=find(abc[0]+abc[1])
elif isinstance(abc[1],列表):
re=查找(abc[:1]+abc[1])
elif isinstance(abc[0],列表):
第一个=查找(abc[0]+abc[1:])
其他:
如果abc[0]>abc[1]:
re=(abc[0],abc[1])
其他:
re=(abc[1],abc[0])
#递归步骤
其他:
#我认为这部分有问题
#将列表展平
如果存在(abc[0],列表):
re=find(abc[0]+abc[1:])
#如果这个元素是整数
其他:
当前=abc[0]
第二,第一=查找(abc[1:])
如果(秒<电流):
re=(第二,第一)
elif(当前>第一)和(第二>=当前):
re=(当前,第一个)
其他:
re=(第一,当前)
返回re
e、 g查找([[]],[12,12],[12],[[]],[[[]]])->(12,12)
查找([1,2,3],[]],[4]])->(2,1)
遍历列表,然后使用isinstance
检查是否需要递归:
def MIN(lst):
mn = None
for item in lst:
if isinstance(item, list) and item:
tmp = MIN(item)
else:
tmp = item
if not mn:
mn = tmp
elif mn > tmp:
mn = tmp
return mn
def find(lst):
mins = []
if not all(isinstance(item, list) for item in lst):
mins.append(MIN(lst))
for item in lst:
if isinstance(item, list):
mins.append(MIN(item))
return filter(lambda x: x==0 or x, mins)
print find([[[]], [12, 12], [[12], []], [[]]])
print find([1, [2, 3], [[]], [4]])
正在解决问题: 您必须在递归中处理空列表的情况。对您的代码进行一个最小的(并且承认有点骇人的)更改将如下所示:
import sys
def find(abc):
#base case
if len(abc) == 2:
if isinstance(abc[0], list) and isinstance(abc[1], list):
re = find(abc[0] + abc[1:])
elif isinstance(abc[1], list):
re = find(abc[:1] + abc[1])
elif isinstance(abc[0], list):
re = find(abc[0] + abc[1:])
# ^^^ fixed typo (ifs could be simplified by dropping first if)
else:
if abc[0] > abc[1]:
re = (abc[0], abc[1])
else:
re = (abc[1], abc[0])
# recursive step
else:
# CHANGE HERE
if len(abc) == 0: # @HACK: handle empty list
return (sys.maxsize, sys.maxsize)
# CHANGE ENDS
if isinstance(abc[0], list):
re = find(abc[0] + abc[1:])
# if this element is integer
else:
current = abc[0]
second, first = find(abc[1:])
if (second < current):
re = (second, first)
elif (current > first) and (second >= current):
re = (current, first)
else:
re = (first, current)
return re # @TODO: possibly filter out maxsize in final result
如果您对稍微不同的返回值感到满意,可以随意删除元组
和[:-1]
替代实施方案:
虽然出于各种原因(例如健壮性、表达能力),我更喜欢上面的重构代码,但这里有一个替代实现,可以说更符合您最初的问题。这个实现背后的主要思想是只检查第一个元素是否是列表?如果是,请展平;如果否,则递归地转到列表的末尾:
def find(abc):
try: # first element is list
return find(abc[0] + abc[1:]) # -> flatten
except: # first element is value
if len(abc) <= 1: return abc # -> either end recursion
return sorted(abc[:1] + find(abc[1:]), reverse=True)[-2:] # -> or recurse over tail
def find(abc):
try:#第一个元素是list
返回查找(abc[0]+abc[1:])#->展平
除此之外:#第一个元素是值
如果len(abc)任一端递归
返回排序(abc[:1]+查找(abc[1]),reverse=True)[-2:]#->或在尾部递归
请注意,返回类型略有不同(列表而不是元组)。您可以用
heapq.nsmallest
替换sorted
(这对于较小的n
)更有效。如果您的用例很大,并且希望避免递归,您可以执行一些迭代魔法并避免递归:
def nested_walker(data):
working_iterators = [iter(data)]
while working_iterators:
current_iterator = working_iterators.pop()
for elem in current_iterator:
if isinstance(elem, list):
working_iterators.append(iter(elem))
else:
yield elem
然后,你可以做如下事情:
data = [[1, [3, 2], [[]], [4]],[[]], [12, 12], [[12], []], [[]]]
sorted_list = sorted(nested_walker(data))
print sorted_list[1]
有更智能的方法来检索第二个最小的整数。为了避免对潜在的巨大大小进行排序,可以使用嵌套的_walker being,因为它是一个生成器函数
正如@stephan所指出的,有一种方法可以使用
heapq
,避免排序:
data = [[1, [3, 2], [[]], [4]],[[]], [12, 12], [[12], []], [[]]]
two_mins = heapq.nsmallest(2, nested_walker(data))
print two_mins[1] # the [0] is the minimum
这是值得检查的,因为它在性能方面可能有点棘手。这里是Python 3中的一个解决方案,它将列表展平、排序并最终返回结果的第二个最小项:
import collections
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
for sub in flatten(el):
yield sub
else:
yield el
a = flatten([[[]], [12, 12], [[12], []], [[]]])
b = flatten([1, [2, 3], [[]], [4]])
print(sorted(a)[1]) # 12
print(sorted(b)[1]) # 2
flatten
功能被直接从中窃取。对于Python 2.7,在flatten中将(str,bytes)
替换为basestring
,您的确切问题是什么?它无法处理空列表的列表,因此如果len(abc)==0,请添加另一个条件:return
如果存在重复值,请考虑所需的行为。例如:data=[1,1,2,3]
应该导致1
或2
?我刚刚意识到,当我想处理空列表时,我忘记了处理空列表。@InWind:很高兴这有帮助。一天后回顾您的问题,我想您可能也对一个简单的递归实现感兴趣(我现在在回答的末尾添加了这个实现)。+1我喜欢这个解决方案。为了避免对一个巨大的列表进行排序,您可以简单地使用def find(abc):返回heapq.nsmallest(2,嵌套的\u walker(abc))
。我确信heapq
有一些方法可以使用,但很匆忙。我现在会更新答案,谢谢!
data = [[1, [3, 2], [[]], [4]],[[]], [12, 12], [[12], []], [[]]]
two_mins = heapq.nsmallest(2, nested_walker(data))
print two_mins[1] # the [0] is the minimum
import collections
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
for sub in flatten(el):
yield sub
else:
yield el
a = flatten([[[]], [12, 12], [[12], []], [[]]])
b = flatten([1, [2, 3], [[]], [4]])
print(sorted(a)[1]) # 12
print(sorted(b)[1]) # 2