Вложенное итеративное отображение / фильтрация - PullRequest
0 голосов
/ 24 октября 2018

Я хотел бы отобразить и отфильтровать элементы вложенных итераций в 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 соответствовал значению встроенных модулей, и добавил больше тестовых случаев.


РЕДАКТИРОВАТЬ

Я написал что-то вроде этого, что делает работу.

( РЕДАКТИРОВАТЬ 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 голосов
/ 24 октября 2018

Насколько я знаю, в стандартной библиотеке такой функции нет, но вы могли бы улучшить возможность повторного использования (и ремонтопригодности и тестируемости) вашего собственного решения, разделив его на более мелкие части, которые затем можно использовать независимо.Во-первых, это функция-обертка для условного применения некоторой функции, а затем две функции для применения любой функции или условной фильтрации элементов вложенных итераций.

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

Таким образом, функцию можно использовать по отдельности, и вынапример, можно инвертировать шаги map и filter.Конечно, вы все еще можете обернуть эти три функции в одну отдельную функцию, обеспечивающую все параметры для более легкого использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...