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']

получить код для достижения желаемых результатов, необходимо внести следующие изменения:

  1. индексы среза должны быть целыми числами. Функция findLoop не работает во второй строке, если список тестов имеет нечетную длину. Принудить тип индексов среза к int округлить (как требуется здесь)

    centre = inds[int(len(inds)/2)-1:int(len(inds)/2)+1]
    
  2. in регистр.

    >>> 'foo' in ['FOO', 'BAR']
    False
    
  3. в 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']

    • как должны вести себя матчи на разных уровнях списка?