Как разрезать список по конкретному пункту?

Я пытаюсь разрезать список по определенным элементам в нем, например, у меня есть такой список:

down = ["a", "b", "c", "d", "b", "e", "r"]

Я хочу:

[["a", "b"]["c", "d", "b"] ["e", "r"]]

который обрезается после каждого появления "b".

Я написал примерно так:

down = ["a", "b", "c", "d", "b", "e", "r"]
up = []
while down is not []:
    up, down = up.append(down[:(down.index("b") + 1)]), down[(down.index("b") + 1):]

Выдает ошибку:

AttributeError: 'NoneType' object has no attribute 'append'

Я не могу понять, что случилось.

У @patrick есть ответ, который вам нужен. насчет того, что не так, вы пытаетесь назначить up с up.append(something). вы не должны назначать при использовании метода / функции списка. В итоге происходит то, что метод append изменяет объект, а затем функция возвращает None. В сочетании с назначением вы изменяете список, но затем связываете имя up со значением «Нет». На следующей итерации вы получите отображаемую ошибку.

Paritosh Singh 25.12.2018 14:35

Спасибо ! Вот в чем я запутался. Я переписал свой код так: down = ["a", "b", "c", "d", "b", "e", "r"] up = [] while "b" in down: up.append(down[:(down.index("b") + 1)]) down = down[(down.index("b") + 1):] up.append(down) @ParitoshSingh

frankzheng43 25.12.2018 14:54

@ frankzheng43 ознакомьтесь с моим ответом, он вам может показаться интересным!

Synthase 18.01.2021 07:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
7
3
2 517
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

Вы получаете сообщение об ошибке, потому что вы назначаете результат функции list.append(), то есть None, на up в

up, down = up.append(down[: (down.index("b") + 1)]), down[...snipp...] 
#          ^^^^^^^^ returns None

list.append - это операция «на месте», которая возвращает None, поэтому в следующей итерации up будет None.

Держитесь ближе к тому, что у вас есть, вы могли бы использовать

down = ["a", "b", "c", "d", "b", "e", "r"]
up = []
while 'b' in down:
    b_index = down.index('b') + 1
    up.append(down[:b_index])
    down = down[b_index:]
up.append(down)

но, на мой взгляд, простая итерация вашего оригинала и сборка подсписок во втором списке более чистая:

k = ["a", "b", "c", "d", "b", "e", "r"]

result = [[]]
for e in k:
    if e != "b":
        result[-1].append(e)
    else:
        result[-1].append(e)
        result.append([])

if result[-1] == []: 
    result.pop() # thx iBug's comment

print(result) # [['a', 'b'], ['c', 'd', 'b'], ['e', 'r']]

Я думаю, что это намного яснее, чем то, что пытается сделать ваш код - ваш «то, что я хочу, ["a", "b"]["c", "d", "b"] ["e", "r"]» не является допустимым питоном.


Немного другая версия кода:

k = ["a", "b", "c", "d", "b", "e", "r"]
b = []
while True:
    try:
        b_idx = k.index("b")
    except: 
        b.append(k)
        break
    else:
        b,k = b+[k[:b_idx+1]],k[b_idx+1:]
print(b) 

Но вам нужно гораздо больше искать в вашем списке через .index() и try: except, поэтому у него будет худшая производительность, чем при простом повторении списка один раз.

result = result[:-1] -> result.pop()
iBug 25.12.2018 14:36

Какие достоинства дв на 2й старый вопрос? Предложение что улучшить?

Patrick Artner 18.01.2021 07:13
down = ["a", "b", "c", "d", "b", "e", "r"]
poslist = []
for pos, item in enumerate(down):
    if item == 'b':
        poslist.append(pos)
answerlist = []
for i in range(len(poslist)):
    if i == 0:
        answerlist.append(down[:poslist[i]+1])
    else:
        answerlist.append(down[poslist[i-1]+1:poslist[i]+1])
answerlist.append(down[poslist[i]+1:])
print (answerlist)
# [['a', 'b'], ['c', 'd', 'b'], ['e', 'r']]
down = ["a", "b", "c", "d", "b", "e", "r"]
indices = [i for i, x in enumerate(down ) if x == "b"]
curr=0
master_list=[]
for item in indices:
    master_list.append(down[curr:item+1])
    print(master_list)
    curr=item+1
if curr !=len(down):
    master_list.append(down[curr:len(down)])
print(master_list)
In [59]: k
Out[59]: ['a', 'b', 'c', 'd', 'b', 'e', 'r', 'l', 'f', 'b', 's']

In [60]: indices = [i for i, x in enumerate(k) if x == "b"]  # all index of 'b'

In [61]: aa = k[:indices[0]+1] # first list

In [62]: bb = k[indices[len(indices)-1]+1:]  # last list

In [63]: for i in range(0, len(indices)-1):
    ...:     print(k[indices[i]+1:indices[i+1]+1]) # remaining list
    ...: 
['c', 'd', 'b']
['e', 'r', 'l', 'f', 'b']

In [64]: aa
Out[64]: ['a', 'b']

In [65]: bb
Out[65]: ['s']

list.append(elem) не возвращает новый список, а только изменяет исходный. Это причина вашей ошибки.

Чтобы исправить свой код без изменения подхода:

down = ["a", "b", "c", "d", "b", "e", "r"]
up = []
while True:
    if 'b' in down: # make sure there is a 'b' in the list
        index = down.index("b") # get the index of the first "b"
        up.append(down[:index + 1]) # save first sublist in up
        down = down [index + 1:] # trim the sublist you already saved 
    else:
        up.append(down) # add the rest of down
        break # leave the loop 
print(up)

Каким был бы такой вопрос без ответа itertools?

В этом случае вы можете использовать groupby с настраиваемым ключом, который считает прошлые вхождения 'b':

from itertools import groupby

class CountKey:
    def __init__(self, what):
        self.what = what
        self.count = 0
    def __call__(self, item):
        count = self.count
        if item == self.what:
            self.count += 1
        return count

up = [list(g) for k, g in groupby(down, CountKey('b'))]

Вы можете составить список индексов, а затем использовать его понимание:

down = ["a", "b", "c", "d", "b", "e", "r"]

n = len(down)
idx = [index+1 for index, value in enumerate(down) if value == 'b']

res = [down[i: j] for i, j in zip([0] + idx, idx + ([n] if idx[-1] != n else []))]

# [['a', 'b'], ['c', 'd', 'b'], ['e', 'r']]

Тернарный оператор [n] if idx[-1] != n else [] используется, чтобы избежать пустого окончательного списка, если последним значением в down является 'b'. Это двухпроходное решение, но в нем используется нарезка списка, а не явное добавление элементов по одному.

Вот простой однострочник, чтобы выполнить эту работу:

import re

d = ["a", "b", "c", "d", "b", "e", "r"]

s = '(?<=b)'

print ([list(x) for x in re.split(s,"".join(d))])

Вывод:

[['a', 'b'], ['c', 'd', 'b'], ['e', 'r']]

Сложность здесь в том, чтобы сохранить разделитель в «левом» подсписке. Метод re.split() может сделать это в сочетании с положительным прогнозом.

Другие вопросы по теме