【发布时间】:2019-09-26 15:21:13
【问题描述】:
所以说我有,list1 = ['the dog', 'the cat', 'cat dog', 'the dog ran home']
and sub_string = '狗'
如何返回 list2 = ['the dog', 'the cat', 'cat dog']
即,返回一个删除了最后一次出现的子字符串的列表?
【问题讨论】:
标签: python python-2.7 string-search
所以说我有,list1 = ['the dog', 'the cat', 'cat dog', 'the dog ran home']
and sub_string = '狗'
如何返回 list2 = ['the dog', 'the cat', 'cat dog']
即,返回一个删除了最后一次出现的子字符串的列表?
【问题讨论】:
标签: python python-2.7 string-search
这里没有内置函数对您有很大帮助,因为扫描list 中的子字符串不是受支持的功能,并且以相反的顺序执行此操作会加倍困难。列表推导也不会起到太大作用,因为让它们有足够的状态来识别您何时发现您的针将涉及向列表推导添加副作用,这使得它变得神秘并违反了函数式编程工具的目的。所以你被困在自己的循环中:
list2 = []
list1iter = reversed(list1) # Make a reverse iterator over list1
for item in list1iter:
if sub_string in item: # Found item to remove, don't append it, we're done
break
list2.append(item) # Haven't found it yet, keep item
list2.extend(list1iter) # Pull all items after removed item
list2.reverse() # Put result back in forward order
另一种方法是按索引扫描,允许您del 它;如果您想就地修改list1,而不是创建一个新的list,这可能是一个更好的解决方案:
for i, item in enumerate(reversed(list1), 1):
if sub_string in item:
del list1[-i]
break
该解决方案适用于制作新副本,只需将所有对list1 的引用更改为list2,并在循环前添加list2 = list1[:]。
在这两种情况下,您都可以通过在for 上放置else: 块来检测是否找到了某个项目;如果else 块触发,您没有break,因为在任何地方都找不到sub_string。
【讨论】:
问题陈述是:删除带有子字符串的元素作为查询
所以,我推断它有两个步骤。
对于模式匹配,我们可以使用re 模块(我们可以使用in 以及ShadowRanger 的答案中提到的)
import re
pattern = re.compile('the dog') # target pattern
my_list = ['the dog', 'the cat', 'cat dog', 'the dog ran home'] # our list
my_list = enumerate(my_list) # to get indexes corresponding to elemnts i.e. [(0, 'the dog'), (1, 'the cat'), (2, 'cat dog'), (3, 'the dog ran home')]
elems = list(filter(lambda x: pattern.search(x[1]), my_list) # match the elements in the second place and filter them out, remember filter in python 3.x returns an iterator
print(elems) # [(0, 'the dog'), (3, 'the dog ran home')]
del my_list[elems[-1][0]] # get the last element and take the index of it and delete it.
编辑
正如 ShadowRunner 所建议的,我们可以使用带有 if 语句而不是 filter 函数的列表推导来优化代码。
elems = [i for i, x in enumerate(my_list) if pattern.search(x)]
【讨论】:
re; OP 的用例不需要模式匹配,只需要子字符串检查。另请注意,通过使用match,此代码不符合 OP 规定的要求; match 包含一个隐式的字符串开头锚点,因此这只会在元素 begins 与子字符串时匹配,而不是在它 包含 子字符串时匹配。您需要 search 进行非锚定收容检查。
elems = [i for i, x in enumerate(my_list) if pattern.search(x)](或不带re、if 'the dog' in x)替换filter 行及其前面的行,因为filter 在您需要lambda 来使用时基本上总是更丑/更慢它。当现有函数完全执行您想要的操作时很好(如果所述函数是用 C 实现的内置函数,它通常更快),但如果不存在,则等效的 listcomp 或genexpr 没有在大多数情况下,lambda 总是更快更清晰。
您可以分两步完成:
例子:
needle = 'the dog'
haystack = ['the dog', 'the cat', 'cat dog', 'the dog ran home']
last = max(loc for loc, val in enumerate(haystack) if needle in val)
result = [e for i, e in enumerate(haystack) if i != last]
print(result)
输出
['the dog', 'the cat', 'cat dog']
有关查找最后一次出现的索引的更多详细信息,请参阅this。
list1 = ['the dog', 'the cat','the dog me', 'cat dog']
sub_string = 'the dog'
for i in list1[::-1]:
print(i)
if sub_string in i:
list1.remove(i)
break
输出 ['狗','猫','狗我','猫狗']
【讨论】:
一种解决方案是逆序遍历输入,在逆序列表中找到索引。之后,使用索引对输入list1进行切片。
idx = next(i for i, s in enumerate(reversed(list1), 1) if sub_string in s)
list2 = list1[:-idx] # If in-place updates are intended, use `del list1[-idx:]` instead
【讨论】: