如何使用列表推导式遍历链表?
我一直在想怎么用列表表达式来遍历一个层级结构,比如链表,但到现在还没找到什么有效的方法。
简单来说,我想把这段代码:
p = self.parent
names = []
while p:
names.append(p.name)
p = p.parent
print ".".join(names)
转换成一行代码,像这样:
print ".".join( [o.name for o in <???>] )
不过,我不太确定怎么在???
的部分进行遍历,以一种通用的方式(如果这甚至可能的话)。我有几个结构,它们都有类似的.parent
属性,我不想为每个结构都写一个生成函数。
补充说明:
我不能使用对象本身的__iter__
方法,因为这个方法已经用来遍历对象内部包含的值了。除了liori的回答,其他大多数答案都是硬编码属性名称,这正是我想避免的。
这是我根据liori的回答进行的调整:
import operator
def walk(attr, start):
if callable(attr):
getter = attr
else:
getter = operator.attrgetter(attr)
o = getter(start)
while o:
yield o
o = getter(o)
4 个回答
1
列表推导式适用于那些可以被迭代的对象,也就是说,它们有一个叫做next()的方法。为了能用这种方式遍历你的数据结构,你需要为它定义一个迭代器。
6
我能想到的最接近的办法就是创建一个父生成器:
# Generate a node's parents, heading towards ancestors
def gen_parents(node):
node = node.parent
while node:
yield node
node = node.parent
# Now you can do this
parents = [x.name for x in gen_parents(node)]
print '.'.join(parents)
2
如果你想让你的解决方案更通用,就要使用一种通用的方法。这是一个类似于固定点的生成器:
def fixedpoint(f, start, stop):
while start != stop:
yield start
start = f(start)
它会返回一个生成器,依次输出 start、f(start)、f(f(start))、f(f(f(start))),等等,只要这些值都不等于 stop。
用法:
print ".".join(x.name for x in fixedpoint(lambda p:p.parent, self, None))
我个人的助手库里有类似的固定点函数,已经用了很多年……它在快速编写小工具时非常有用。