【问题标题】:Python - Filter nested inside of map produces unexpected outputPython - 嵌套在地图内的过滤器会产生意外的输出
【发布时间】:2021-02-19 22:28:24
【问题描述】:

我有一个文件名(字符串)列表和一组由浮点数组成的 ls。最初,我想根据预先确定的表达式过滤与 ls 的每个元素匹配的所有文件: 我将所有实际上是整数的浮点数转换为整数并将其输入.format 以创建适当的搜索字符串(exprs)。这会产生预期的字符串序列。我现在想使用 re.search 过滤“文件”,但据我所知,我需要为 exprs 的每个输出使用不同的过滤器。所以我把它嵌套在一个 map 函数中:

t = 'Matrix'
exprs = map('{}_spike_{}_D1_1'.format , cycle([t]) ,(int(x) if x.is_integer() else x for x in ls))
y = map(lambda f:filter(lambda i : re.search(f,i), files), exprs)

Print(next(exprs)) 产生预期的输出,即'Matrix_spike_50_D1_1'。如果我“冻结” re.search 中的表达式,即通过执行 b = next(exprs)re.search(b, [...]) 我得到预期的输出(即文件名,正确选择)。 但是当我尝试使用map 来消耗exprs 的所有输出并返回结果filter([...]) 时,我得到了

  1. 过滤器对象而不是地图对象
  2. 两个相同过滤器对象,当通过while True 详尽地运行它时,捕获所有StopIterations 并恢复

如何修改它以返回过滤每个 exprs 返回的文件?

【问题讨论】:

    标签: python filter functional-programming iterator


    【解决方案1】:

    如果我正确理解您的问题,您有一个文件列表,例如:

    files = ['a', 'b', 'Matrix_spike_2_D1_1', 'c', 'Matrix_spike_4_D1_1']
    

    还有一个浮点数列表,应该是整数(但可能不是全部都是):

    ls = [1.1, 2.0, 3.0, 4.0, 5.0]
    

    ls 整数列表中,构造名称“Matrix_spike_2_D1_1”、“Matrix_spike_3_D1_1”等,然后从files 列表中选择满足rex.search 调用的文件。当然,不使用^$ 锚点的search 方法不会完全匹配,所以我想知道您是否真的打算使用fullmatch 方法。

    首先,你有:

    t = 'Matrix'
    exprs = map('{}_spike_{}_D1_1'.format , cycle([t]) ,(int(x) if x.is_integer() else x for x in ls))
    

    我相信这被简化为:

    exprs = map('Matrix_spike_{}_D1_1'.format, (int(x) for x in ls if x.is_integer())
    

    请注意,我只从ls 中选择整数值,我相信这是您的意图。按照你的方法,我相信最简单的补救方法是定义一个函数filter_func

    import re
    
    
    ls = [1.1, 2.0, 3.0, 4.0, 5.0]
    files = ['a', 'b', 'Matrix_spike_2_D1_1', 'c', 'Matrix_spike_4_D1_1']
    exprs = list(map(re.compile, map('Matrix_spike_{}_D1_1'.format, (int(x) for x in ls if x.is_integer()))))
    
    def filter_func(f):
        for expr in exprs:
            if expr.search(f):
                return True
        return False
    
    matched_files = list(filter(filter_func, files))
    print(matched_files)
    

    打印:

    ['Matrix_spike_2_D1_1', 'Matrix_spike_4_D1_1']
    

    或者使用更“实用”但效率可能较低的方法:

    import re
    import operator
    import functools
    
    
    ls = [1.1, 2.0, 3.0, 4.0, 5.0]
    files = ['a', 'b', 'Matrix_spike_2_D1_1', 'c', 'Matrix_spike_4_D1_1']
    exprs = list(map(re.compile, map('Matrix_spike_{}_D1_1'.format, (int(x) for x in ls if x.is_integer()))))
    filter_func = lambda f: functools.reduce(operator.or_, map(lambda expr: bool(expr.search(f)), exprs), False)
    matched_files = list(filter(filter_func, files))
    print(matched_files)
    

    打印:

    ['Matrix_spike_2_D1_1', 'Matrix_spike_4_D1_1']
    

    但我相信你的方法不是最有效的。您应该对files 列表的每个元素进行一次正则表达式搜索。在上面的示例中,该正则表达式将是:

    rex = re.compile('Matrix_spike_(?:2|3|4|5)_D1_1')
    

    在上面的正则表达式中,您将匹配files 列表中的每个元素与您正在查找的所有 4 个可能的文件名。这将代码简化为:

    import re
    
    
    ls = [1.1, 2.0, 3.0, 4.0, 5.0]
    files = ['a', 'b', 'Matrix_spike_2_D1_1', 'c', 'Matrix_spike_4_D1_1']
    sub_rex = '|'.join(str(int(x)) for x in ls if x.is_integer())
    rex = re.compile('Matrix_spike_(?:' +  sub_rex + ')_D1_1');
    matched_files = list(filter(rex.search, files))
    print(matched_files)
    

    打印:

    ['Matrix_spike_2_D1_1', 'Matrix_spike_4_D1_1']
    

    如果您要对文件名进行完全匹配(相等),那么以下代码将是最有效的,因为它将您要查找的名称添加到一个集合中,并且每次比较都将是一个常数时间查找:

    ls = [1.1, 2.0, 3.0, 4.0, 5.0]
    files = ['a', 'b', 'Matrix_spike_2_D1_1', 'c', 'Matrix_spike_4_D1_1']
    sought_files = {f'Matrix_spike_{int(x)}_D1_1' for x in ls if x.is_integer()}
    matched_files = list(filter(lambda f: f in sought_files, files))
    print(matched_files)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多