Python递归反向打印列表项

2 投票
2 回答
1948 浏览
提问于 2025-04-17 02:20

我在用Python的时候,想要反向读取一个字符串列表。当我找到我感兴趣的那个项目后,我想把从那个点到列表末尾的所有项目都打印出来。我可以不使用递归来做到这一点,而且效果很好,但我觉得用递归的方式会更优雅一些。:)

没有递归的例子:

items = ['item1', 'item2', 'item3', 'item4', 'item5']

items_of_interest = []
items.reverse()
for item in items:
    items_of_interest.append(item)
    if item == 'item3':
        break
    else:
        continue

items_of_interest.reverse()
print items_of_interest
['item3', 'item4', 'item5']

更新:

为了让问题更清楚,这个列表实际上是从日志文件中用grep命令提取的一组字符串。这个字符串集合可能会重复,我只想要最后一组。

2 个回答

1

这里不需要用递归的方法。对于从列表中找到某个项目最后一次出现的位置到列表末尾的切片问题,可以定义一个辅助函数。

>>> def rindex(s, x):
...     for i, y in enumerate(reversed(s)):
...         if x == y:
...             return -i-1
...     raise ValueError
... 
>>> items[rindex(items, "b"):]
['b', 'f']

这个辅助函数可以叫做 rindex,因为在Python中有一个 rindex 方法可以用来找到字符串中某个子串最后一次出现的位置。

如果你必须用递归的方法(可能是作业要求),那么可以考虑用下面的伪代码来思考这个问题(还没有完全写出来)。

def tail_from(list, x):
    return tail_from_aux(list, x, [])

def tail_from_aux(list, element, accumulated):
    if list is empty:
        return []
    elif list ends with element
        return element::accumulated
    else:
        last = list[-1]
        return tail_from_aux(list[:-1], element, last::accumulated)

不过,这种方法会消耗很多内存,遍历整个列表(效率不高),而且不符合Python的风格。虽然在其他语言中可能合适,但在Python中不推荐使用。

由于你提到的问题是关于文件,尤其是日志文件,你可能无法把这个问题简化为数组搜索。因此,可以看看这个链接:使用Python反向读取文件,那里有一些有趣的答案和一些可以跟进的链接。

如果可以的话,也可以考虑将 tacawkgrep 混合使用。

5

递归并不会让这个问题变简单,反而会让它变得更复杂。

for i, item in enumerate(reversed(items), 1):
    if item == 'item3':
        items_of_interest = items[-i:]
        break
else:
    # 'item3' wasn't found

在我看来,这似乎是最简单有效的解决方法。你只需要从列表的末尾遍历到 'item3',因为 reversed 会返回一个迭代器。

编辑:如果你不介意遍历整个列表来创建一个反向版本,你可以使用:

i = list(reversed(items)).index('item3')
items_of_interest = items[-i-1:]

这个方法甚至更简单。如果 'item3' 不在列表中,它会抛出一个错误。我使用 list(reversed()) 而不是 [:] 然后 reverse(),因为这样只需要遍历一次列表,而不是两次。

编辑 2:根据你对其他答案的评论,我的第一个版本正好满足你的需求——从末尾搜索这个项目,而不需要遍历整个列表。问题中的版本需要遍历列表来反转它,我的第二个版本也是如此。

你原始代码的一个稍微修改过但更有效的版本是:

items_of_interest = []
for item in reversed(items):
    items_of_interest.append(item)
    if item == 'item3':
        break
items_of_interest.reverse()

撰写回答