Удалить элементы из списка, начиная со списка префиксов

У меня есть список строк и список префиксов. Я хочу удалить все элементы из списка строк, которые начинаются с префикса из списка префиксов.

Я использовал цикл for, но почему он не работает?

list_of_strings = ['test-1: foo', 'test-2: bar', 'test-3: cat']
list_of_prefixes = ['test1', 'test-2']

final_list = []
for i in list_of_strings:
    for j in list_of_prefixes:
        if not i.startswith(j):
            final_list.append(i)
            
print(list(set(final_list)))

В настоящее время вывод

['test-3: cat', 'test-1: foo', 'test-2: bar']

Результат, который я хочу получить, это

final_list = ['test-3: cat']
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
5
0
111
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Вы можете использовать startswith() с flag:

def _filter(list_of_strings, list_of_prefixes):
    final_list = []
    for i in list_of_strings:
        flag = False
        for j in list_of_prefixes:
            if i.startswith(j):
                flag = True
                break
        if not flag:
            final_list.append(i)
    return final_list


list_of_strings = ['test-1: foo', 'test-2: bar', 'test-3: cat']
list_of_prefixes = ['test-1', 'test-2']

print(_filter(list_of_strings, list_of_prefixes))

Принты

['test-3: cat']

Проблема с вашей реализацией заключается в том, что для каждого префикса вы просматриваете весь list_of_strings и добавляете к конечному результату final_list все элементы, которые начинаются не с этого префикса, включая строки, которые могут начинаться с других префиксов в list_of_prefixes (которые , в конечном счете, вы не захотите оставлять).

Например:

  1. в первой итерации list_of_strings элементом является 'test-1: foo', поэтому вы перебираете list_of_prefixes, первый префикс — 'test-1'. Круто, ты не добавляешь 'test-1: foo' к final_list.
  2. Следующий префикс теперь — 'test-2'. Вы проверяете его на 'test-1: foo', и он проходит проверку if not i.startswith(j), так что в конечном итоге вы все равно добавляете 'test-1: foo' к final_list!
  3. То же самое происходит и со следующими итерациями.

В качестве быстрого исправления вашей собственной реализации, без особых изменений в вашей логике, я предлагаю: вместо того, чтобы начинать с пустого набора и добавлять к нему, начните с набора всех list_of_strings и удаляйте ненужное в своих итерациях!

Так:

final_list = set(list_of_strings)
for i in list_of_strings:
    for j in list_of_prefixes:
        if i.startswith(j):
            final_list.remove(i)

Со временем, по мере вашего знакомства с Python, вы поймете, что большинство этих базовых операций (например, фильтрация) уже реализованы встроенными модулями. Есть много способов сделать это без пользовательских циклов. Например, используя filter и списки:

[s for s in list_of_strings if not any(filter(s.startswith, list_of_prefixes))]

Какая забавная головоломка. Я предполагаю, что первая запись в префиксах — «test-1».

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

Поскольку вы эффективно фильтруете только то, что хотите видеть, вы можете достичь своей цели следующим образом:

list_of_strings = ['test-1: foo', 'test-2: bar', 'test-3: cat']
list_of_prefixes = ['test-1', 'test-2']

final_list = list_of_strings
for prefix in list_of_prefixes:
    result = list(filter(lambda x: x.startswith(prefix), final_list))
    for ele in result:
        final_list.remove(ele)

print(final_list)

Я сохранил исходные массивы на тот случай, если они понадобятся вам в дальнейшем в вашем коде.

этот код изменяет исходные списки, final_list = list_of_strings не создает копию

juanpa.arrivillaga 19.06.2024 09:02
Ответ принят как подходящий

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

С помощью списков, выражений-генераторов и any это очень просто.

>>> list_of_strings = ['test-1: foo', 'test-2: bar', 'test-3: cat']
>>> list_of_prefixes = ['test1', 'test-2']
>>> filtered = [
...   s 
...   for s in list_of_strings 
...   if not any(s.startswith(p) for p in list_of_prefixes)
... ]
>>> filtered
['test-1: foo', 'test-3: cat']

Обратите внимание, что 'test-1: foo' не начинается с 'test1' или 'test-2'. Если бы вы хотели, чтобы list_of_prefixes включал 'test-1', вы получили бы ожидаемый результат.

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

list_of_strings = ['test-1: foo', 'test-2: bar', 'test-3: cat']
list_of_prefixes = ['test1', 'test-2']

new = [x for x in list_of_strings if x.split(':')[0] not in list_of_prefixes]
print(new)

Выход:

['test-1: foo', 'test-3: cat']

Вы можете упростить свой код. startswith изначально принимает несколько префиксов и возвращает True, если один из них присутствует. Однако этот аргумент должен быть кортежем, а не списком, поэтому я переименовал его.

list_of_strings = ['test-1: foo', 'test-2: bar', 'test-3: cat']
# switch to a tuple
tuple_of_prefixes = ('test-1', 'test-2')
 
final_list = []
for i in list_of_strings:
    if not i.startswith(tuple_of_prefixes):
        final_list.append(i)
 
print(list(set(final_list)))

(Кроме того, согласно вашему изложению, я думаю, вы хотели исключить test-1, а не test1.)

Демо: https://ideone.com/0NvI5z

Очевидно, если хотите, это можно превратить в понимание списка.

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