Список расщепления 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

Это выглядит немного грязно, но он отлично работает для вложенных ключевых слов начала и конца, поэтому подсети могут быть сформированы внутри подсписок, но это не работает для нескольких ключевых слов начала и конца, которые не находятся внутри eachother. Вложенность еще не важна, поэтому любая помощь будет оценена по достоинству.

Ответы

Ответ 1

Одним из творческих способов было бы сбросить ваш список в строку 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'

Преимущество состоит в том, что его легко следовать, он отлично работает для произвольных вложенных списков и обнаруживает, что структура неверна. Вы должны убедиться, что ваши слова не содержат ".

Ответ 2

Один способ использования нарезки:

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

Ответ 3

множественный старт, заканчивается (на основании ответа Марка Толонен)

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

Ответ 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

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

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

    • Должна ли сублимироваться только в исходном списке или внутри подсписок?
  • ['foo', 'world'], затем ['test', 'bar']

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