Python 在给定的开始/结束关键字处将列表拆分为子列表

Posted

技术标签:

【中文标题】Python 在给定的开始/结束关键字处将列表拆分为子列表【英文标题】:Python splitting list to sublists at given start/end keywords 【发布时间】:2018-07-24 19:57:47 【问题描述】:

如果我有一个清单,说

lst = ['hello', 'foo', 'test', 'world', 'bar', 'idk']

我想把它分成一个子列表,以'foo''bar' 作为开始和结束关键字,这样我就可以得到

lst = ['hello', ['foo', 'test', 'world', 'bar'], 'idk']

我目前这样做的方式如下。

def findLoop(t):   
    inds = [index for index, item in enumerate(t) if item in ["FOO", "BAR"]]
    centre = inds[(len(inds)/2)-1:(len(inds)/2)+1]
    newCentre = t[centre[0]:centre[1]+1]
    return t[:centre[0]] + [newCentre] + t[centre[1]+1:]

def getLoops(t):
    inds = len([index for index, item in enumerate(t) if item in ["FOO", "BAR"]])
    for i in range(inds):
        t = findLoop(t)
    return t

这看起来有点乱,但它对于嵌套的开始/结束关键字非常有效,因此子列表可以在子列表内部形成,但它不适用于多个开始/结束关键字不在彼此内部。嵌套并不重要,因此我们将不胜感激。

【问题讨论】:

【参考方案1】:

一种使用切片的方法:

>>> lst = ['hello', 'foo', 'test', 'world', 'bar', 'idk']
>>> a=lst.index('foo')
>>> b=lst.index('bar')+1
>>> lst[a:b] = [lst[a:b]]
>>> lst
['hello', ['foo', 'test', 'world', 'bar'], 'idk']

【讨论】:

是的,但是 OP 也要求多个开始,结束。我冒昧地做了一个函数。 @AntonvBR OP 的示例不起作用,也没有说明他的意思。请添加您自己的答案,请不要编辑我的答案。【参考方案2】:

多个开始,结束(基于 Mark Tolonen 的回答)

lst = ['hello', 'foo', 'test', 'world', 'bar', 'idk','am']
t = [('foo','test'),('world','idk')]

def sublists(lst, t):
    for start,end in t:
        a=lst.index(start)
        b=lst.index(end)+1
        lst[a:b] = [lst[a:b]]
    return lst

print(sublists(lst,t)) 

返回:

 ['hello', ['foo', 'test'], ['world', 'bar', 'idk'], 'am']

【讨论】:

我不知道这在 Op 案例中是否重要,但如果它们出现不止一次,则会失败:['A', 'foo', 'test', 'bar', 'B', 'foo', 'test2', 'bar'] 应该变为 ['A', ['foo', 'test', 'bar'], 'B', ['foo', 'test2', 'bar']] 而不是 ['A', ['foo', 'test', 'bar'], 'B', 'foo', 'test2', 'bar']。还有 @987654326 @。它应该分组为['foo', 'bar'](作为您的代码)还是['foo', 'bar', 'bar'] 相关但不清楚 OP 打算如何使用它。当然,您也可以构建错误异常。无论如何,好点!【参考方案3】:

一种创造性的方法是将您的列表转储到 JSON 字符串,在需要的地方添加 [],然后将您的 JSON 字符串解析回 Python 嵌套列表:

import json
lst = ['hello', 'foo', 'test', 'world', 'bar', 'idk']
start_keywords = ['world', 'foo', 'test']
end_keywords = ['bar', 'idk', 'foo']
dump = json.dumps(lst)

for k in start_keywords:
    dump = dump.replace(f'"k"', f'["k"')

for k in end_keywords:
    dump = dump.replace(f'"k"', f'"k"]')

json.loads(dump)
# ['hello', ['foo'], ['test', ['world', 'bar'], 'idk']]
json.loads(dump)[2][1][0]
# 'world'

优点是易于理解,它适用于任意嵌套列表,并且它可以检测结构是否不正确。不过,您需要确保您的文字中不包含"

【讨论】:

哇,这非常有效,即使对于我计划稍后实施的东西也是如此。谢谢!【参考方案4】:

使用切片,不支持嵌套列表:

>>> lst = ['hello', 'foo', 'test', 'world', 'bar', 'idk']
>>> start_idx = lst.index('foo')
>>> end_idx = lst.index('bar')
>>> lst[:start_idx] + [lst[start_idx:end_idx+1]] + lst[end_idx+1:]
['hello', ['foo', 'test', 'world', 'bar'], 'idk']

【讨论】:

【参考方案5】:

要让您的代码达到预期的效果,您需要进行以下更改:

    切片索引必须是整数。如果您的测试列表长度为奇数,则您的 findLoop 函数在第二行失败。将切片索引的类型强制为 int 以向下舍入(此处需要)

    centre = inds[int(len(inds)/2)-1:int(len(inds)/2)+1]
    

    in 区分大小写。

    >>> 'foo' in ['FOO', 'BAR']
    False
    

    在 getLoops 中,您只需搜索配对中的第一个元素,因为 findLoops 会在每次调用时从一对单词中分出子列表。

    inds = len([index for index, item in enumerate(t) if item in ['foo']])
    

Try it online!


但是,正如您所注意到的,您的代码非常混乱,其他答案显示了如何使用 list().index() 来获得更好的效果。

如果您想进一步查找嵌套子列表,则需要进一步说明您希望它的行为方式。考虑以下问题:

子列表['foo', 'bar'],然后['test', 'world']

应该只在初始列表中进行子列表,还是在子列表中也出现?

子列表['foo', 'world'],然后['test', 'bar']

列表不同级别上的匹配应如何表现?

【讨论】:

以上是关于Python 在给定的开始/结束关键字处将列表拆分为子列表的主要内容,如果未能解决你的问题,请参考以下文章

在每个谓词 scala 处将字符串列表拆分为多个列表

Kotlin 在多个索引处将 Arraylist 拆分为多个部分

Python - 根据 2 个关键字拆分带有长字符串的列表

尝试在给定阈值处将所有像素更改为黑白

在给定偏移量处将音频剪辑插入原始音频文件

Python根据条件拆分列表值