【问题标题】:How to filter list based on another list containing wildcards?如何根据另一个包含通配符的列表过滤列表?
【发布时间】:2014-04-29 15:06:04
【问题描述】:

如何根据包含部分值和通配符的另一个列表过滤列表?以下是我目前所拥有的示例:

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

【问题讨论】:

    标签: python list glob


    【解决方案1】:

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

    【讨论】:

    • 好一个!我知道一种使用接受正则表达式的list 子类的方法。不知道这个。
    【解决方案2】:

    您也可以使用 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']
    

    这样,您甚至可以泛化您的 filterfunc 以使用多个模式集:

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

    当然,您可以轻松升级您的 filterfunc 以接受模式集中的正则表达式。

    【讨论】:

      【解决方案3】:

      我认为您的用例最简单的方法是使用 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']
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-06
        • 1970-01-01
        • 2017-12-08
        • 2018-02-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多