将平面列表转换为嵌套列表

时间:2011-07-16 22:10:53

标签: python recursion

使用Python

我想要以下内容:

[1, 2, 2, 1, 2, 3, 2, 3]

转变为:

[1, 2, 2, [1, 2, 3], 2, 3]

规则:浏览列表中的每个项目。如果我们点击2后跟1创建一个列表并在该列表中包含该1,直到我们达到3,包括该列表,然后关闭列表并继续。这就像1是3是括号。

对于我认为在这种情况下可能需要的递归算法,我不是很好。

一如既往地谢谢。

5 个答案:

答案 0 :(得分:3)

仍然记住@Walter对你的问题的评论是正确的,这是你所要求的愚蠢的实现,受到你的问题的最后一点的启发,你建议13可以替换为[13]

>>> import re
>>> s = repr([1, 2, 2, 1, 2, 3, 2, 3])
>>> s = re.sub('1', '[1', s)
>>> s = re.sub('3', '3]', s)
>>> l = eval(s)
>>> l
[[1, 2, 2, [1, 2, 3], 2, 3]]

它的作用是处理列表的表示(字符串)并替换您建议使用正则表达式的方式。最后,它评估字符串(返回列表)。

我把这个实现称为“愚蠢”,因为它可以解决这个问题,但它很丑陋而且非常简单。也就是说,它可以解决问题,所以如果您只是将它用于一次性转换某些数据,那么您需要使用...

HTH!

答案 1 :(得分:2)

def whatever(a):
    b = []
    tmp = []
    last = None

    for elem in a:
        if tmp:
            tmp.append(elem)
            if elem == 3:
                b.append(tmp)
                tmp = []
        elif last == 2 and elem == 1:
            tmp.append(1)
        else:
            b.append(elem)
        last = elem
    return b

print whatever([1, 2, 2, 1, 2, 3, 2, 3])

答案 2 :(得分:1)

这是一个有趣的问题!这是我的解决方案:

def treeize(treeizable, tree=None, stopper=object()):
    if tree is None:
        tree = []

    if treeizable[:1] == [stopper]:
        tree.append(treeizable.pop(0))       
        return tree
    elif treeizable[0:2] == [2, 1]:
        tree.append(treeizable.pop(0))
        subtree = []
        treeize(treeizable, subtree, stopper=3)
        tree.append(subtree)
        return treeize(treeizable, tree, stopper)
    elif treeizable:
        tree.append(treeizable.pop(0))
        return treeize(treeizable, tree, stopper)
    else:
        return tree

此函数接收应转换为嵌套列表treeizable的平面列表treestopper参数标记当前列表何时完成 - 这是嵌套列表或顶层列表。 (由于stopper的默认值是object的实例,因此使用默认值调用列表时不可能存在阻塞,因为object的实例之间存在不同本身)。

def treeize(treeizable, tree=None, stopper=object()):

为了简化我们的工作,tree的默认值为None,如果它具有默认值,则将其设置为列表。这是因为it is problematic to have mutable values as default parameter objects。此外,每次都必须使用空列表键入函数会很烦人。

    if tree is None:
        tree = []

如果平面列表的第一个值是“阻塞”,则将其添加到树中并返回树。请注意,通过使用treeizable.pop(0)我实际上从平面列表中删除值。由于仅在定义嵌套列表时设置了止动器,因此,当我们找到它时,不再需要完成:“子树”(即嵌套列表)已完成。另外,请注意我使用列表的切片获取列表的第一个元素。我之所以这样做,是因为输入if treeizable and treeizable[0] == stopper很无聊。由于切片没有不存在索引的问题,我得到了切片并将其与另一个仅使用塞子的列表进行比较:

    if treeizable[:1] == [stopper]:
        tree.append(treeizable.pop(0))       
        return tree

如果列表的开头是“beginner”,那么我从列表中弹出第一个元素,将其附加到树中并创建一个新树 - 即一个空列表。现在我用剩余的列表和空子树调用treeize(),同时传递3作为停止值。 treeize()将递归生成一个新树,我将其附加到我的初始树。之后,只需使用列表的剩余部分(不再包含子树的元素)和原始列表调用treeize()。请注意,塞子应与原始呼叫接收的塞子相同。

    elif treeizable[0:2] == [2, 1]:
        tree.append(treeizable.pop(0))
        subtree = []
        treeize(treeizable, subtree, stopper=3)
        tree.append(subtree)
        return treeize(treeizable, tree, stopper)

如果以前的条件都没有(第一个元素是一个塞子,列表的开头是[2, 1])是真的,那么我验证列表中是否有东西。在这种情况下,我弹出第一个元素,添加到树中并使用列表的其余部分调用treeize()

    elif treeizable:
        tree.append(treeizable.pop(0))
        return treeize(treeizable, tree, stopper)

如果前一个条件都不成立,那么我们就有一个空列表。这意味着所有元素都放在树中。只需将树返回给用户:

    else:
        return tree

这似乎有效:

>>> treeize.treeize([1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 3, 2, 4, 5, 3,  3, 2, 3, 4])
[1, 2, 2, [1, 2, 2, [1, 2, 2, [1, 2, 3], 2, 4, 5, 3], 3], 2, 3, 4]

你的问题有尝试的功课。原则上,我们不应该回答它,但它是如此有趣,我无法自助:)如果它是一个功课,但是,不要尝试使用这个解决方案作为你,因为它是错的,你的老师肯定会发现它在Google上:P

答案 3 :(得分:0)

我喜欢状态机:

from itertools import izip, tee

def pairwise(iterable):
    a, b = tee(iterable)
    next(b)
    return izip(a, b)

class Flat(object):
    def append_next(self, alist, e0, e1):
        alist.append(e0)
        if e0 == 2 and e1 == 1:
            alist.append([])
            self.__class__ = Nested
    def append_last(self, alist, e):
        alist.append(e)

class Nested(object):
    def append_next(self, alist, e0, e1):
        alist[-1].append(e0)
        if e0 == 3:
            self.__class__ = Flat
    def append_last(self, alist, e):
        alist[-1].append(e)

def nested(flat_list):
    if len(flat_list) <= 1:
        return list(flat_list)
    state = Flat()
    nested_list = []
    for x, y in pairwise(flat_list):
        state.append_next(nested_list, x, y)
    state.append_last(nested_list, y)
    return nested_list

s = [1, 2, 2, 1, 2, 3, 2, 3]

print nested(s)

给出:

[1, 2, 2, [1, 2, 3], 2, 3]

但这可能更像是pythonic:

def nested(flat_list):
    if len(flat_list) <= 1:
        return list(flat_list)
    pairs = pairwise(flat_list)
    nested_list = []
    while True:
        for x, y in pairs:
            nested_list.append(x)
            if x == 2 and y == 1:
                nested_list.append([])
                break
        else:
            nested_list.append(y)
            break
        for x, y in pairs:
            nested_list[-1].append(x)
            if x == 3:
                break
        else:
            nested_list[-1].append(y)
            break
    return nested_list

答案 4 :(得分:0)

Pease bear with me - 现在是2:50(晚上) - 这是我的版本 - 不是非常美丽,但对我来说效果很好:

def buildNewList(inputList):
    last = 0
    res = []
    for i,c in enumerate(inputList):
        if i == 0:
            prev = c
        if i < last:
            continue
        if c == 1 and prev == 2:
            if 3 in inputList[i:]:
                last = i + 1 + inputList[i:].index(3)
                res.append(buildNewList(inputList[i: last]))
            else:
                last = len(inputList)
                res.append(buildNewList(inputList[i:len(inputList)]))
        else:
            res.append(c)
        prev = c
    return res


l1 = buildNewList([1, 2, 2, 1, 2, 3, 2, 3])
>>> [1, 2, 2, [1, 2, 3], 2, 3]

l2 = buildNewList([1, 2, 2, 1, 2, 3, 2, 1, 2, 3])
>>> [1, 2, 2, [1, 2, 3], 2, [1, 2, 3]]

l3 = buildNewList([1,2,3,1,2,3])
>>> [1, 2, 3, 1, 2, 3]

l4 = buildNewList([1,2,1,1,2,1])
>>> [1, 2, [1, 1, 2, [1]]]