Python 将列表拆分为给定 start/end 关键字的子列表
Python splitting list to sublists at given start/end keywords
如果我要列表,请说
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
这看起来有点乱,但它对嵌套的start/end关键字非常有效,因此可以在子列表内部形成子列表,但它不适用于不在内部的多个start/end关键字彼此。嵌套还不重要,所以任何帮助将不胜感激。
使用切片的一种方式:
>>> lst = ['hello', 'foo', 'test', 'world', 'bar', 'idk']
>>> a=lst.index('foo') # locate start word
>>> b=lst.index('bar')+1 # locate end word
>>> lst[a:b] = [lst[a:b]] # replace list slice with a list of the slice
>>> lst
['hello', ['foo', 'test', 'world', 'bar'], 'idk']
使用切片,不支持嵌套列表:
>>> 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']
多个开始、结束(基于 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))
Returns:
['hello', ['foo', 'test'], ['world', 'bar', 'idk'], 'am']
一种创造性的方法是将您的列表转储为 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'
优点是易于理解,适用于任意嵌套列表,并且可以检测结构是否不正确。不过,您需要确保您的文字不包含 "
。
为了让您的代码达到预期的效果,您需要进行以下更改:
切片索引必须是整数。如果您的测试列表长度为奇数,您的 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']])
但是,正如您所注意到的,您的代码非常混乱,其他答案显示了如何使用 list().index()
来获得更好的效果。
如果您想进一步查找嵌套的子列表,则需要进一步说明您希望它的行为方式。考虑以下问题:
子列表 ['foo', 'bar']
,然后 ['test', 'world']
- 子列表应该仅出现在初始列表中,还是也出现在子列表中?
子列表 ['foo', 'world']
,然后 ['test', 'bar']
- 列表不同级别的匹配应该如何表现?
如果我要列表,请说
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
这看起来有点乱,但它对嵌套的start/end关键字非常有效,因此可以在子列表内部形成子列表,但它不适用于不在内部的多个start/end关键字彼此。嵌套还不重要,所以任何帮助将不胜感激。
使用切片的一种方式:
>>> lst = ['hello', 'foo', 'test', 'world', 'bar', 'idk']
>>> a=lst.index('foo') # locate start word
>>> b=lst.index('bar')+1 # locate end word
>>> lst[a:b] = [lst[a:b]] # replace list slice with a list of the slice
>>> lst
['hello', ['foo', 'test', 'world', 'bar'], 'idk']
使用切片,不支持嵌套列表:
>>> 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']
多个开始、结束(基于 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))
Returns:
['hello', ['foo', 'test'], ['world', 'bar', 'idk'], 'am']
一种创造性的方法是将您的列表转储为 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'
优点是易于理解,适用于任意嵌套列表,并且可以检测结构是否不正确。不过,您需要确保您的文字不包含 "
。
为了让您的代码达到预期的效果,您需要进行以下更改:
切片索引必须是整数。如果您的测试列表长度为奇数,您的 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']])
但是,正如您所注意到的,您的代码非常混乱,其他答案显示了如何使用 list().index()
来获得更好的效果。
如果您想进一步查找嵌套的子列表,则需要进一步说明您希望它的行为方式。考虑以下问题:
子列表
['foo', 'bar']
,然后['test', 'world']
- 子列表应该仅出现在初始列表中,还是也出现在子列表中?
子列表
['foo', 'world']
,然后['test', 'bar']
- 列表不同级别的匹配应该如何表现?