从列表中删除不包含特定字符串的项

3
我有一个 URL 列表,想要删除不包含 imgur 或 youtube 的任何链接。
somelist = ['google.com', 'facebook.com', 'imgur.com/9utwj.gif', 'youtube.com/ofskdofk', 'yahoo.com']
approved = ['imgur','youtube']

for app in approved:
    matching = [s for s in somelist if app in s]
    for match in matching:
        somelist.remove(match)
print somelist

这返回

['google.com', 'facebook.com', 'yahoo.com']

所以从逻辑上讲,我认为如果将此更改为不在s中,则会使它更快。
matching = [s for s in somelist if app not in s]

它会删除所有不包含已批准URL的内容。然而,它没有返回任何东西。


1
mymaliciousite.com/evilpage?ignoreme=youtube+imgur我的恶意网站.com/恶意页面?忽略我=YouTube+Imgur - Eric
5个回答

10
你可以使用 any 来检查 approved 中的任何一个字符串是否在 somelist 中每个网址中出现:
somelist = ['google.com', 'facebook.com', 'imgur.com/9utwj.gif', 'youtube.com/ofskdofk', 'yahoo.com']
approved = ['imgur','youtube']


somelist[:] = [url for url in somelist if any(sub in url for sub in approved)]

print(somelist)
['imgur.com/9utwj.gif', 'youtube.com/ofskdofk']

any会在第一次匹配到时短路,如果有多个子字符串的URL,它仍然只会添加一次该URL。

somelist [:]表示我们使用列表推导式的效率来更改原始列表/对象,而不是使用list.remove和常规for循环。


2
也许你可以解释一下,你认为这里的切片操作符给了你什么。 - jwilner
如果我理解正确,您只是在赋值的左侧使用somelist[:]来获得副作用(并没有明确地要求问题)-更改原始列表。通常在Python中(如果不需要副作用),我们会简单地分配给somelist,如果它在其他任何地方都没有被引用,垃圾收集器将删除原始列表。 - pabouk - Ukraine stay strong

1
为了对代码版本进行最小更改,为什么不只取你知道是好的属性(查找匹配项并执行相关操作),然后更改正在执行的操作,例如将其附加到新列表而不是从旧列表中删除?即:
newlist = []
for app in approved:
    matching = [s for s in somelist if app in s]
    for match in matching:
        newlist.append(match)
print newlist

然后当你想做更高级的事情时,你可以将其转化为没有副作用的函数...

[编辑:我看到这基本上是与上面的答案相同的方法,而且还与我的交叉!去投票那个。:-)]


0

简而言之:

results = [url for url in somelist for app in approved if app in url]

1
这可能会重复条目(即如果两个应用程序在同一网址中)。 - jwilner
@jwilner:没错,发现得好。 - Eric

0

这个代码使用了OR运算符,且没有第二个FOR循环。结果相同。

#!/usr/bin/python

somelist = ['google.com', 'facebook.com', 'imgur.com/9utwj.gif', 'youtube.com/ofskdofk', 'yahoo.com']
approved = ['imgur','youtube']

L=[]

for s in somelist:
        if s.find('imgur') != -1 or s.find('youtube') != -1:
            L.append(s)

somelist=L

print somelist

输出

['imgur.com/9utwj.gif', 'youtube.com/ofskdofk']

-3
#!/usr/bin/python

somelist = ['google.com', 'facebook.com', 'imgur.com/9utwj.gif', 'youtube.com/ofskdofk', 'yahoo.com']
approved = ['imgur','youtube']

L=[]

for s in somelist:
    for app in approved:
        if s.find(app) != -1:
            L.append(s)

somelist=L

print somelist

输出

['imgur.com/9utwj.gif', 'youtube.com/ofskdofk']

3
可以,这样做是可行的,但离Pythonic的习惯相去甚远。 - jwilner
2
你正在使用列表创建引用,这通常不是一个好主意。如果两个子字符串都出现,你也会添加相同的URL两次。 - Padraic Cunningham
3
需要使用短路逻辑来避免重复。在追加后添加一个“break”。 - jwilner
如果你能数到二,就不会得到重复项。每个“somelist”中的“s”只被检查两次。它可以包含“imgur”或“youtube”。你可以只使用一个if条件和一个OR运算符来获得相同的结果。我又写了一个for循环,只是因为“approved”可以无限扩展。但是,如果“somelist”包含1,你肯定会得到重复项。我在下面又发了一篇文章来说明OR的工作原理。 - Alex Ivanov
我可以轻松地数到 2,这就是我知道当您有一个包含两个迭代的内部循环并且您正在检查的字符串 s 包含这两个子字符串时,它将被添加两次的原因。 - Padraic Cunningham
那又怎样?只要不在两个不同的地方放置相同的子字符串,你就不必搜索两次。 - Alex Ivanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接