Python - удалить любой элемент из списка строк, который является подстрокой другого элемента
Итак, начиная со списка строк, как показано ниже
string_list = ['rest', 'resting', 'look', 'look', 'it', 'spit']
Я хочу удалить любой элемент из списка, который является подстрокой другого элемента, давая результат, например...
string_list = ['resting', 'look', 'spit']
У меня есть код, который это делает, но он смущающе уродливый и, вероятно, бесполезно сложный. Есть ли простой способ сделать это в Python?
Ответы
Ответ 1
Первый строительный блок: подстрока.
Вы можете использовать in
для проверки:
>>> 'rest' in 'resting'
True
>>> 'sing' in 'resting'
False
Далее мы собираемся выбрать наивный метод создания нового списка. Мы добавим элементы по одному в новый список, проверяя, являются ли они подстрокой или нет.
def substringSieve(string_list):
out = []
for s in string_list:
if not any([s in r for r in string_list if s != r]):
out.append(s)
return out
Вы можете ускорить его, сортируя, чтобы уменьшить количество сравнений (в конце концов, более длинная строка никогда не может быть подстрокой строки более короткой/равной длины):
def substringSieve(string_list):
string_list.sort(key=lambda s: len(s), reverse=True)
out = []
for s in string_list:
if not any([s in o for o in out]):
out.append(s)
return out
Ответ 2
Здесь возможно решение:
string_list = ['rest', 'resting', 'look', 'looked', 'it', 'spit']
def string_set(string_list):
return set(i for i in string_list
if not any(i in s for s in string_list if i != s))
print(string_set(string_list))
выдает:
set(['looked', 'resting', 'spit'])
Примечание. Я создаю набор (используя выражение генератора), чтобы удалить, возможно, дублированные слова, поскольку кажется, что порядок не имеет значения.
Ответ 3
Еще один лайнер:
[string for string in string_list if len(filter(lambda x: string in x,string_list)) == 1]
должен быть достаточно читабельным, а не пифоном.
Ответ 4
Здесь один метод:
def find_unique(original):
output = []
for a in original:
for b in original:
if a == b:
continue # So we don't compare a string against itself
elif a in b:
break
else:
output.append(a) # Executed only if "break" is never hit
return output
if __name__ == '__main__':
original = ['rest', 'resting', 'look', 'looked', 'it', 'split']
print find_unique(original)
Он использует тот факт, что мы можем легко проверить, является ли одна строка подстрокой другого с помощью оператора in
. Он по существу проходит через каждую строку, проверяет, является ли она подстрокой другого, и добавляет себя в список вывода, если это не так.
Отпечатает ['resting', 'looked', 'split']
Ответ 5
Вот один-лайнер, который делает то, что вы хотите:
filter(lambda x: [x for i in string_list if x in i and x != i] == [], string_list)
Пример:
>>> string_list = ['rest', 'resting', 'look', 'looked', 'it', 'spit']
>>> filter(lambda x: [x for i in string_list if x in i and x != i] == [], string_list)
['resting', 'looked', 'spit']
Ответ 6
Здесь не оптимальный способ, используйте только, если списки невелики:
for str1 in string_list:
for str2 in string_list:
if str1 in str2:
string_list.remove(str1)
Ответ 7
Вот эффективный способ сделать это (относительно вышеупомянутых решений;)), поскольку этот подход значительно сокращает количество сравнений между элементами списка. Если у меня есть огромный список, я бы определенно пошел с этим, и, конечно, вы можете превратить это решение в функцию лямбда, чтобы он выглядел небольшим:
string_list = ['rest', 'resting', 'look', 'looked', 'it', 'spit']
for item in string_list:
for item1 in string_list:
if item in item1 and item!= item1:
string_list.remove(item)
print string_list
Вывод:
>>>['resting', 'looked', 'spit']
Надеюсь, что это поможет!
Ответ 8
Вот еще один способ сделать это. Предполагая, что у вас есть отсортированный список для начала, и вам не нужно делать просеивание на месте, мы можем просто выбрать самые длинные строки за один проход:
string_list = sorted(string_list)
sieved = []
for i in range(len(string_list) - 1):
if string_list[i] not in string_list[i+1]:
sieved.append(string_list[i])