Я пытаюсь заменить элементы в списке на основе соответствия подстроки
у меня есть следующий список
x = ['D-cat', 'cat', 'C-Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'L-cat']
Если есть два элемента, например. Д-кот и кот, я хочу заменить элемент с префиксом на элемент без префикса. то есть D-cat нужно заменить на cat. Так же хочу заменить все префикс-xxx с xxx.
Я устал от следующего, используя replace.
x = [animal.replace('D-cat','cat') for animal in x]
Ожидаемый результат:
x = ['cat', 'cat', 'Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'cat']
Я не уверен, как это можно реализовать для всех элементов.
Я хотел бы попросить некоторые предложения.
Обновлено: Прецедент
x =['C-Rab 6-bit', 'Rab 6-bit']
ожидаемый результат:
x=['Rab 6-bit', 'Rab 6-bit']
Теперь я вижу, что у вас также есть L-cat, но игнорируйте его, так что я предполагаю, что это последовательные элементы?
и опубликуйте ожидаемый результат






Если вы уверены, что нужное слово и префикс разделены дефисом, а дефис не появляется ни в префиксе, ни в слове, это может сработать:
lookup_dict = {animal:True for animal in x if '-' not in animal}
def get_word(animal):
without_prefix = animal.split('-')[-1]
return without_prefix if lookup_dict.get(without_prefix) else animal
x = [get_word(animal) for animal in x]
Примечание. Более общий подход заключается в использовании регулярного выражения. Этот подход, хотя и специфический, намного эффективнее по сравнению с использованием регулярных выражений.
вы можете сделать это с помощью основного цикла for:
mylist = ['D-cat', 'cat', 'C-Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'L-cat']
for i in range(len(mylist)):
for j in range(len(mylist)):
if mylist[j] in mylist[i]:
mylist[i] = mylist[j]
print (mylist)
выход:
['cat', 'cat', 'Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'cat']
Обновлено: тестовый пример
mylist = ['C-Rab 6-bit', 'Rab 6-bit']
ouput >> ['Rab 6-bit', 'Rab 6-bit']
не уверен, имеет ли это значение, но разница между этим подходом и подходом с регулярным выражением заключается в том, что он не проверяет, как выглядит префикс, - он будет заменять «мой маленький кролик», «джек-кролик» или «-кролик» .
@Stael Это легко решить, передав второй параметр «1» в split. регулярное выражение является излишним для такого типа манипуляций со строками.
@ncica не проходит тестовый пример, опубликованный в редакции исходного поста.
С простым пониманием списка и функцией str.find:
x = ['D-cat', 'cat', 'C-Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'L-cat']
res = [s[s.find('-')+1:]
if ('-' in s and s[s.find('-')+1:] in x) else s for s in x[:]]
print(res)
Выход:
['cat', 'cat', 'Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'cat']
Чтобы избежать двойного цикла, я бы один раз перешел к хеш-животным без префикса, а затем заменил:
#Assuming no one letter animal.
#The condition allows for animals with '-'
#in the name by insisting '-' not be the second character.
#('-' in a) would not have allowed '-' in the name.
animal_set = set(a for a in x if a[1] != '-')
for i in range(len(x)):
animal = x[i].split('-',1)[-1]
if animal in animal_set: x[i]= animal
Я думаю, что это лучше, чем настаивать на понимании, и скорость будет иметь значение для длинных списков (n ^ 2 по сравнению со сложностью n). Это включает в себя использование оператора in в исходном списке.
Я бы также сказал, что регулярное выражение в выбранном вами решении абсолютно бесполезно - здесь сработает обычное разбиение или индексация строки. Если вам действительно нужен один лайнер для цикла, вы можете использовать:
[a.split('-',1)[-1] if a.split('-',1)[-1] in animal_set else a for a in x]
но теперь вам придется разделиться дважды, а не один раз, так что я был бы против этого.
Обратите также внимание на «1», которую я передаю для разделения — это будет обрабатывать дополнительные тире, такие как L-complex-animal, разделяя их на «L» и «complex-animal».
код работает для ввода в моем исходном сообщении. Однако 'C-Rab 6-bit', 'Rab 6-bit' этот тестовый пример не проходит. Ожидаемый результат 'Rab 6-bit', 'Rab 6-bit'
@ Наташа, это == должно быть != в первой строке, мой плохой.
Превосходно! можно ли будет это сделать? ['eta-C-Rab 6-bit', 'C-Rab 6-bit', 'Rab 6-bit'] ожидаемый результат: ['Rab 6-bit', 'Rab 6-bit', 'Rab 6-bit']
@ Наташа Это требует нового вопроса. В вашем исходном вопросе префикс всегда был одной буквой (S,R,C). eta-C — это 4-буквенное слово, в котором даже есть тире. Вам нужно будет указать, как вы узнаете, является ли что-то префиксом или частью имени, что слишком сильно изменит вопрос.
Если вы в конечном итоге зададите новый вопрос, обязательно дайте образец списка полный, объясните, как вы определяете, является ли элемент в списке именем (без префикса), и вы можете дать ссылку на него в комментариях здесь а я посмотрю (и другие заглянут).
для любителей одного вкладыша (не обязательно рекомендуется):
x = ['D-cat', 'cat', 'C-Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'L-cat']
[re.sub('\w-', '', i) if re.sub('\w-', '', i) in x else i for i in x]
# ['cat', 'cat', 'Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'cat']
Вы можете использовать set для более быстрой проверки, если в вашем списке есть животное без префикса.
x = ["D-cat", "cat", "C-Rabbit", "Rabbit", "R-rat", "S-rat", "L-cat", "C-Rab 6-bit", "Rab 6-bit"]
x_set = set(x)
processed_animals = []
for animal in x:
no_prefix_animal = animal.split("-", 1)[-1]
if no_prefix_animal in x_set:
animal = no_prefix_animal
processed_animals.append(animal)
print(processed_animals)
# ['cat', 'cat', 'Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'cat', 'Rab 6-bit', 'Rab 6-bit']
Одно решение с itertools.groupby:
x = ['D-cat', 'cat', 'C-Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'L-cat']
from itertools import groupby
out = []
s = sorted(enumerate(x), key=lambda k: (k[1].split()[0].split('-', maxsplit=1)[-1], len(k[1])))
for v, g in groupby(s, lambda k: k[1].split()[0].split('-', maxsplit=1)[-1]):
l = [*g]
remove_prefix = not '-' in l[0][-1].split()[0]
to_replace = l[0][-1]
out.extend([(i[0],to_replace) if remove_prefix else i for i in l])
print([i[1] for i in sorted(out)])
Отпечатки:
['cat', 'cat', 'Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'cat']
Тестовый случай с x = ['C-Rab 6-bit', 'Rab 6-bit'] отпечатками:
['Rab 6-bit', 'Rab 6-bit']
Вы можете использовать enumerate с пониманием списка:
import re
def _strip(x):
return [re.sub('^[A-Z]\-', '', a) if any(a.endswith(c) and not re.findall('^[A-Z]\-', c) for c in x) \
else a for i, a in enumerate(x)]
print(_strip(['D-cat', 'cat', 'C-Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'L-cat']))
print(_strip(['C-Rab 6-bit', 'Rab 6-bit']))
Выход:
['cat', 'cat', 'Rabbit', 'Rabbit', 'R-rat', 'S-rat', 'cat']
['Rab 6-bit', 'Rab 6-bit']
Всегда ли два элемента следуют друг за другом? Какой префикс вы хотите поставить в случае
R-ratиS-rat? Что, если бы было толькоratпосле?