我有一个表示数据结构遍历的字符串列表。我想将链接列表遍历折叠成更紧凑的表示。为此,我想计算相邻next
和prev
链接的数量,并将它们合并为一个整数。
以下是我想要进行的转换的示例:
['modules'] --> ['modules']
['modules', 'next'] --> ['modules', 1]
['modules', 'prev'] --> ['modules', -1]
['modules', 'next', 'next', 'next', 'txt'] --> ['modules', 3, 'txt']
['modules', 'next', 'prev', 'next', 'txt'] --> ['modules', 1, 'txt']
['super_blocks', 'next', 's_inodes', 'next'] --> ['super_blocks', 1, 's_inodes', 1]
每个next
链接计为+1,每个prev
为-1。相邻的next
和prev
s相互抵消。它们可以按任何顺序排列。
我有一个有效的解决方案,但我很难找到一个令人满意的优雅和Pythonic解决方案。
答案 0 :(得分:6)
您可以使用生成器:
def links(seq):
it = iter(seq)
while True:
el = next(it)
cnt = 0
try:
while el in ['prev', 'next']:
cnt += (1 if el == 'next' else -1)
el = next(it)
finally:
if cnt != 0:
yield cnt
yield el
print list(links(['modules', 'next', 'prev', 'next', 'txt']))
值得注意的是,包含相同数量的next
和prev
的序列将被完全删除。如果这就是你想要的,我很容易改变代码来生成0
。(我认为这些要求有点不清楚。)
答案 1 :(得分:1)
这是我想到的最简单的方法。简单明了是理解,调试和未来维护的宝贵品质。
def process(l):
result = []
count = 0
keepCount = False
for s in l:
if s == "next":
count += 1
keepCount = True
elif s == "prev":
count -= 1
keepCount = True
else:
if keepCount:
result.append(count)
count = 0
keepCount = False
result.append(s)
# end if
# end for
if keepCount:
result.append(count)
return result
# end process()
我确实更喜欢NPE对发电机的使用。 (我可以通过将'result.append()'更改为'yield'来轻松转换。)他的(原始)答案几乎与我的相同,但我在事件中包括0计数下一个/上一个令牌的数量相等。
答案 2 :(得分:1)
一点reduce()
怎么样?
def collapse(lst):
was_link = [False] # No nonlocal in Python 2.x :(
def step(lst, item):
val = { 'prev': -1, 'next': 1 }.get(item)
if was_link[0] and val:
lst[-1] += val
else:
lst.append(val or item)
was_link[0] = bool(val)
return lst
return reduce(step, [[]] + lst)
答案 3 :(得分:1)
怎么样:
def convert(ls):
last = None
for x in ls:
if x == 'prev': x = -1
if x == 'next': x = +1
if isinstance(x, int) and isinstance(last, int):
x += last
elif last: # last is not None if you want zeroes
yield last
last = x
yield last