如何根据包含通配符的另一个列表过滤列表?

9 投票
3 回答
3505 浏览
提问于 2025-04-18 04:46

我想知道怎么根据另一个列表来筛选一个列表,这个列表里面包含了一些部分值和通配符。下面是我目前的例子:

l1 = ['test1', 'test2', 'test3', 'test4', 'test5']
l2 = set(['*t1*', '*t4*'])

filtered = [x for x in l1 if x not in l2]
print filtered

这个例子得到的结果是:

['test1', 'test2', 'test3', 'test4', 'test5']

不过,我想根据 l2 来限制结果,想要得到以下内容:

['test2', 'test3', 'test5']

3 个回答

1

我觉得对于你的情况,最简单的方法就是用Python的 in 来检查子字符串(不过这意味着你得去掉你的星号):

def remove_if_not_substring(l1, l2):
    return [i for i in l1 if not any(j in i for j in l2)]

这是我们的数据:

l1 = ['test1', 'test2', 'test3', 'test4', 'test5']
l2 = set(['t1', 't4'])

然后用这些数据来调用我们的函数:

remove_if_not_substring(l1, l2)

返回结果是:

['test2', 'test3', 'test5']
1

你也可以用filter()来代替列表推导式,这样做的好处是你可以更方便地更换你的过滤函数,增加灵活性:

>>> l1 = ['test1', 'test2', 'test3', 'test4', 'test5']
>>> l2 = set(['*t1*', '*t4*'])
>>> filterfunc = lambda item: not any(fnmatch(item, pattern) for pattern in l2)
>>> filter(filterfunc, l1)
Out: ['test2', 'test3', 'test5']
>>> # now we don't like our filter function no more, we assume that our l2 set should match on any partial match so we can get rid of the star signs:
>>> l2 = set(['t1', 't4'])
>>> filterfunc = lambda item: not any(pattern in item for pattern in l2)
>>> filter(filterfunc, l1)
Out: ['test2', 'test3', 'test5']

这样一来,你甚至可以把你的过滤函数做得更通用,可以处理多个模式集合:

>>> from functools import partial
>>> def filterfunc(item, patterns):
    return not any(pattern in item for pattern in patterns)
>>> filter(partial(filterfunc, patterns=l2), l1)
Out: ['test2', 'test3', 'test5']
>>> filter(partial(filterfunc, patterns={'t1','test5'}), l1)
Out: ['test2', 'test3', 'test4']

当然,你还可以轻松地升级你的过滤函数,让它接受正则表达式作为模式集合,比如说。

11

使用 fnmatch 模块和列表推导式结合 any() 函数:

>>> from fnmatch import fnmatch
>>> l1 = ['test1', 'test2', 'test3', 'test4', 'test5']
>>> l2 = set(['*t1*', '*t4*'])
>>> [x for x in l1 if not any(fnmatch(x, p) for p in l2)]
['test2', 'test3', 'test5']

撰写回答