Мне было интересно, есть ли лучший способ решить эту проблему.
У меня есть такой список:
imp_list=["aa","daa","ab","as","aem",
"aum","aw","aa","acm","at",
"ar","aa_imp","daa_imp","ab_imp",
"as_imp"]
Я хочу выбрать все строки с _imp
суффикс, плюс все строки, у которых нет _imp
партнер.
Это потому что aa_imp
это просто модифицированная версия aa
, и для меня, в широком смысле, это реплика. Итак, я создал эту функцию:
def imputed_handler(my_list):
imp=[x for x in my_list if "imp" in x]
cleaned_imp=set(map(lambda x: x.replace("_imp",""),imp))
not_imp=[x for x in my_list if "imp" not in x]
set_list=set(my_list)
no_replica=list(set_list-cleaned_imp)
print(no_replica)
return no_replica
Запуск кода, как описано выше
test=imputed_handler(imp_list)
Получаю следующий результат:
['at', 'acm', 'aw', 'ar', 'daa_imp', 'aem', 'as_imp', 'ab_imp', 'aa_imp', 'aum']
Существуют ли лучшие решения? Спасибо за уделенное время, и дайте мне знать, если что-то непонятно 🙂
2 ответа
Во-первых, поскольку вы ищете строки, заканчивающиеся на _imp
, x.endswith("_imp")
вероятно более надежен, чем "imp" in x
.
Во-вторых, поскольку мы хотим только удалить _imp
когда это суффикс и поскольку мы знаем его длину, мы можем использовать нарезку строки, чтобы удалить последние 4 символа. Это означает, что мы случайно не поворачиваем x_impabc_imp
в xabc
вместо x_impabc
или что-то. Предполагая, что это не то, что мы хотим делать. Может быть, а может и нет, может, мы никогда не получим такой ввод, так что это не имеет значения, я понятия не имею.
Я также думаю, что было бы неплохо передать суффикс в качестве параметра. Может быть, когда-нибудь это изменится. Возможно, другая часть программы аналогичным образом использует другой суффикс. Не помешает подготовиться.
Но в целом ваш подход хорош. Вы найдете _imp
одни, вы выясняете, что они заменяют, вы удаляете те, которые были заменены.
Самое интересное, что вы можете выполнить первые два шага одновременно за один проход по списку ввода. Например, вы можете сделать это:
def imputed_handler(my_list, suffix="_imp"):
my_set = set(my_list)
cleaned_imp = set(item[:-len(suffix)] for item in my_set if item.endswith(suffix))
return list(my_set - cleaned_imp)
Хотя в этот момент цикл может быть более понятным:
def imputed_handler(my_list, suffix="_imp"):
my_set = set(my_list)
for item in my_list:
if item.endswith(suffix):
my_set.discard(item[:-len(suffix)])
return list(my_set)
PEP 8
В Руководство по стилю кода Python перечисляет несколько соглашений, которым должны следовать программы Python. Вещи как:
- пробелы вокруг бинарных операторов (
imp = [...]
иset_list = set(my_list)
). - пробелы после запятой (например,
""), imp))
Побочные эффекты
Вы возвращаете результат из imputed_hander
; не должен печатать изнутри.
Типовые подсказки и строки документов
Что def imputed_handler(my_list)
? Что оно делает? Что my_list
список? Что возвращается?
from typing import List
def imputed_handler(my_list: List[str]) -> List[str]:
"""
Filter a list of strings, removing `"xyz"` if `"xyz_imp"` is found.
Return the filtered list.
"""
Теперь у нас есть (плохое) описание и мы можем видеть типы аргументов и возвращаемых значений.
Улучшенный код
Как упоминалось в ответе Сары Дж, .endswith()
предпочтительнее простой проверки, содержится ли строка поиска где-нибудь внутри оригинала.
Преобразование списка в набор, а затем обратно в список разрушает исходный порядок списков. Вот возможное улучшение решения Сары:
from typing import List
def imputed_handler(my_list: List[str], suffix: str = "_imp") -> List[str]:
"""
A good description here.
"""
unwanted = {item.removesuffix(suffix) for item in my_list if item.endswith(suffix)}
return [item for item in my_list if item not in unwanted]
А set
создается только из префикса элементов, заканчивающихся на _imp
. Это должно привести к меньшему объему памяти, что set(my_list) - cleaned_imp
. Поскольку это set
, то in
оператор $ O (1) $, фильтрация списка выполняется быстро.
- 2
Примечание,
typing.List
теперь не рекомендуется вы можете просто использоватьlist[str]
в Python 3.9+ или импортируйте аннотации из PEP 563 — «Импорт изtyping
не рекомендуется. Из-за PEP 563 и намерение свести к минимуму влияние набора текста на время выполнения, это исключение не будет генерировать DeprecationWarnings. «— Пейлонрайз
Еще одна возможная настройка — вместо того, чтобы брать «foo_imp» и генерировать «foo» для удаления, это спрашивать для каждого «foo», есть ли «foo_imp» в наборе.
my_set = set(my_list); return [s for s in my_list if s + suffix not in my_set]
. Нужно быть осторожным, эквивалентен ли он для таких цепочек, какimputed_handler(["aa", "aa_imp", "aa_imp_imp"])
но я думаю, что это … Это также соответствует вашему описанию «удаление"xyz"
если"xyz_imp"
найдено «, что является наиболее четким определением, которое я могу придумать.— Бени Чернявский-Паскин
Начиная с Python 3.9 вы также можете использовать
item.removesuffix(suffix)
.— Келли Банди
@KellyBundy Отлично. Я не нашел этого, так как по какой-то причине я все еще использую 3.8.5, но это полезно знать.
— Сара Дж.