Python 如何使用递归根据谓词将序列插入列表列表

Python 如何使用递归根据谓词将序列插入列表列表,python,list,Python,List,我目前正在练习递归,我经常遇到的一个问题是将序列切割成列表。我试图自己解决,但没有成功: 我的代码: def cut_sequence_at(seq, pred) -> list: if not seq: return [[]] if len(seq) == 1: return [seq] rest = cut_sequence_at(seq[1:], pred) if pred(seq[0]): return

我目前正在练习递归,我经常遇到的一个问题是将序列切割成列表。我试图自己解决,但没有成功:

我的代码:

def cut_sequence_at(seq, pred) -> list:
    if not seq:
        return [[]]
    if len(seq) == 1:
        return [seq]
    rest = cut_sequence_at(seq[1:], pred)
    if pred(seq[0]):
        return [[seq[0]] + rest[0]] + rest[1:]
    else:
        return [[seq[0]]] + rest

# input
seq = [8,6,3,4,12,8,7,2,1]
pred = lambda x: x % 2 != 0
cut_sequence_at(seq, pred)

# Output
[[8], [6], [3, 4], [12], [8], [7, 2], [1]]

# Expected output
[[8, 6], [3, 4, 12, 8], [7, 2], [1]]
显然我的逻辑有问题,但我不知道如何解决。如果不使用非标准的lib模块,您将如何解决该问题?

您可以使用
next()
函数查找满足条件的第一个项目的位置。返回该部分,其余部分递归。找到断裂位置需要从第二个项目开始,这样您就不会生成空零件

def cut(seq,cond):
    i = next((i for i, n in enumerate(seq[1:], 1) if cond(n)), None)
    if i is None: return [seq]            # no item meeting condition
    return [seq[:i]] + cut(seq[i:], cond) # first part + recursion

seq = [8,6,3,4,12,8,7,2,1]
pred = lambda x: x % 2 != 0
print(cut(seq, pred))
[[8, 6], [3, 4, 12, 8], [7, 2], [1]]

最具python风格的解决方案是使用迭代解决方案,而不是递归解决方案。如果您想要一个遵循类似Lisp的head,tail方法的递归解决方案,最简单的方法是定义一个递归助手函数,该函数接受最终状态已确定的块列表、当前正在增长的块以及列表的其余部分。它检查列表其余部分的标题。如果满足谓词,则增长块(如果非空)被添加到已知块列表中,并初始化新的增长块。否则,头部会被钉在生长块的末端。这在理论上具有如下优势(如果python优化了尾部调用,这将很重要)


您的
else
子句总是创建一个列表列表,其中第一个元素是长度为1的列表。它有效!非常感谢。
def cut_sequence_at(seq, pred):
    def helper(settled,active,rest):
        if rest == []:
            if active != []:
                settled.append(active)
            return settled
        head, tail = rest[0],rest[1:]
        if pred(head):
            if active != []:
                settled.append(active)
            active = [head]
        else:
            active.append(head)
        return helper(settled,active,tail)
    return helper([],[],seq)

seq = [8,6,3,4,12,8,7,2,1]
pred = lambda x: x % 2 != 0
print(cut_sequence_at(seq, pred)) #[[8, 6], [3, 4, 12, 8], [7, 2], [1]]