Python разделение списка на подсписки в заданных ключевых словах начала/конца
если бы у меня был список, скажите
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, не находящихся внутри друг друга. Бытие вложенные еще не важны, поэтому любая помощь будет оценена по достоинству.
5 ответов
одним из творческих способов было бы сбросить ваш список в в формате 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'
преимущество в том, что легко следовать, он отлично работает для произвольных вложенных списков и определяет, правильна ли структура. Вы должны убедиться, что ваши слова не содержат "
, хотя.
один из способов использования нарезки:
>>> 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']
множественный старт, концы (на основе ответа Марка Толонена)
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']
использование нарезки без поддержки вложенных списков:
>>> 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']
получить код для достижения желаемых результатов, необходимо внести следующие изменения:
-
индексы среза должны быть целыми числами. Функция 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()
для лучшего эффекта.
если вы хотите продолжить это, чтобы найти вложенные подсписки, это потребует дополнительных разъяснений о том, как вы хотите, чтобы это вело себя. Рассмотреть следующее проблемы:
-
sublisting
['foo', 'bar']
, потом['test', 'world']
- должны sublisting произойти только в начальном списке, или подсписков внутри тоже?
-
sublisting
['foo', 'world']
, потом['test', 'bar']
- как должны вести себя матчи на разных уровнях списка?