Замена элементов в списке

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

у меня есть следующий список

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

Всегда ли два элемента следуют друг за другом? Какой префикс вы хотите поставить в случае R-rat и S-rat? Что, если бы было только rat после?

kabanus 24.07.2019 14:20

Теперь я вижу, что у вас также есть L-cat, но игнорируйте его, так что я предполагаю, что это последовательные элементы?

kabanus 24.07.2019 14:21

и опубликуйте ожидаемый результат

RomanPerekhrest 24.07.2019 14:23
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
143
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Если вы уверены, что нужное слово и префикс разделены дефисом, а дефис не появляется ни в префиксе, ни в слове, это может сработать:

 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 24.07.2019 14:39

@Stael Это легко решить, передав второй параметр «1» в split. регулярное выражение является излишним для такого типа манипуляций со строками.

kabanus 24.07.2019 14:43

@ncica не проходит тестовый пример, опубликованный в редакции исходного поста.

Natasha 24.07.2019 15:03

С простым пониманием списка и функцией 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'

Natasha 24.07.2019 14:59

@ Наташа, это == должно быть != в первой строке, мой плохой.

kabanus 24.07.2019 15:09

Превосходно! можно ли будет это сделать? ['eta-C-Rab 6-bit', 'C-Rab 6-bit', 'Rab 6-bit'] ожидаемый результат: ['Rab 6-bit', 'Rab 6-bit', 'Rab 6-bit']

Natasha 24.07.2019 18:24

@ Наташа Это требует нового вопроса. В вашем исходном вопросе префикс всегда был одной буквой (S,R,C). eta-C — это 4-буквенное слово, в котором даже есть тире. Вам нужно будет указать, как вы узнаете, является ли что-то префиксом или частью имени, что слишком сильно изменит вопрос.

kabanus 24.07.2019 19:42

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

kabanus 24.07.2019 19:43

для любителей одного вкладыша (не обязательно рекомендуется):

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

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