在链接列表中展平“下一个”和“上一个”链接

时间:2013-03-21 21:43:52

标签: python

我有一个表示数据结构遍历的字符串列表。我想将链接列表遍历折叠成更紧凑的表示。为此,我想计算相邻nextprev链接的数量,并将它们合并为一个整数。

以下是我想要进行的转换的示例:

['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。相邻的nextprev s相互抵消。它们可以按任何顺序排列。

我有一个有效的解决方案,但我很难找到一个令人满意的优雅和Pythonic解决方案。

4 个答案:

答案 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']))

值得注意的是,包含相同数量的nextprev的序列将被完全删除。如果这就是你想要的,我很容易改变代码来生成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