嵌套的迭代映射/过滤

时间:2018-10-24 10:14:43

标签: python python-3.x list nested

我想在Python中映射和过滤匹配特定条件的嵌套可迭代元素,例如:

items = [func(item) if map_condition(item) else item for item in items if filter_condition(item)]

但一般化为嵌套的可迭代对象,因此像这样的输入:

items = [[1, 2], [[3, 4, 4.0, 5], 5], 6.0, 'ciao', 7, 8, {1, 2, 3}]

像这样应用函数nested_map_filter(items, func, map_condition, filter_condition)

new_items = nested_filter_map(items, str, lambda x: isinstance(x, int), lambda x: not isinstance(x, str))
new_items = nested_filter_map(items, str, None, None)
new_items = nested_filter_map(items, str, None, lambda x: not isinstance(x, float))
new_items = nested_filter_map(items, str, lambda x: isinstance(x, int), None)
new_items = nested_filter_map(items, str, lambda x: isinstance(x, int), lambda x: not isinstance(x, float))

分别将导致以下结果:

# [['1', '2'], [['3', '4', 4.0, '5'], '5'], 6.0, '7', '8', {'2', '1', '3'}]
# [['1', '2'], [['3', '4', '4.0', '5'], '5'], '6.0', 'ciao', '7', '8', {'2', '1', '3'}]
# [['1', '2'], [['3', '4', '5'], '5'], 'ciao', '7', '8', {'2', '1', '3'}]
# [['1', '2'], [['3', '4', 4.0, '5'], '5'], 6.0, 'ciao', '7', '8', {'2', '1', '3'}]
# [['1', '2'], [['3', '4', '5'], '5'], 'ciao', '7', '8', {'2', '1', '3'}]

标准库中是否有标准构造或某些东西可以做到这一点?

编辑:我改进了术语,以使map / filter与内建函数的含义相匹配,并增加了更多的测试用例。


编辑

我写了这样的东西,可以完成工作。

EDIT 2 )我的问题更多:我是在重新发明轮子吗?将其编写为发电机可能/方便吗?

def deep_filter_map(
        items,
        func=None,
        map_condition=None,
        filter_condition=None,
        avoid=(str, bytes),
        max_depth=-1):
    if func is None:
        def func(x): return x
    if map_condition is None:
        def map_condition(_): return True
    if filter_condition is None:
        def filter_condition(_): return True
    container = type(items)
    new_items = []
    for item in items:
        try:
            no_expand = avoid and isinstance(item, avoid)
            if no_expand or max_depth == 0 or item == next(iter(item)):
                raise TypeError
        except TypeError:
            if filter_condition(item):
                new_items.append(func(item) if map_condition(item) else item)
        else:
            new_items.append(
                deep_filter_map(
                    item, func, map_condition, filter_condition, avoid, max_depth - 1))
    return container(new_items)

1 个答案:

答案 0 :(得分:1)

据我所知,标准库中没有这样的功能,但是您可以将自己的解决方案分成较小的部分,然后分别使用,以提高其可重用性(以及可维护性和可测试性)。首先,是一个包装器函数,用于有条件地应用某些函数,然后是两个函数,用于将任何函数应用到或有条件地过滤嵌套可迭代对象的元素。

def cond_apply(cond, func):
    return lambda x: func(x) if cond(x) else x

def deep_map(func, lst, types=(list, tuple, set)):
    if isinstance(lst, types):
        return type(lst)(deep_map(func, x) for x in lst)
    else:
        return func(lst)

def deep_filter(cond, lst, types=(list, tuple, set)):
    if isinstance(lst, types):
        return type(lst)(deep_filter(cond, x) for x in lst if isinstance(x, types) or cond(x))
    else:
        return lst

items = [[1, 2], [[3, 4, 4.0, 5], 5], 6.0, 'ciao', 7, 8, {1, 2, 3}]
print(deep_map(cond_apply(lambda x: isinstance(x, int), str),
               deep_filter(lambda x: not isinstance(x, str), items)))
# [['1', '2'], [['3', '4', 4.0, '5'], '5'], 6.0, '7', '8', {'1', '3', '2'}]

通过这种方式,该功能可以单独使用,例如反转mapfilter步骤。当然,您仍然可以将这三个函数包装到另一个提供所有参数的单个函数中,以方便使用。