如何使用列表推导式遍历链表?

1 投票
4 回答
1832 浏览
提问于 2025-04-15 12:22

我一直在想怎么用列表表达式来遍历一个层级结构,比如链表,但到现在还没找到什么有效的方法。

简单来说,我想把这段代码:

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))

我个人的助手库里有类似的固定点函数,已经用了很多年……它在快速编写小工具时非常有用。

撰写回答