Написание функции для фильтрации данных. Функция в качестве аргумента функции

Задача звучит следующим образом.

Создать функции query, select и field_filter для манипуляций с данными. Эти функции должны предоставлять возможность выбирать необходимые столбцы и производить фильтрацию по этим столбцам. Аргументы функций заданы.

Пример:

friends = [
    {'name': 'Sam', 'gender': 'male', 'sport': 'Basketball'},
    {'name': 'Emily', 'gender': 'female', 'sport': 'volleyball'},
]
result = query(
    friends, select('name', 'gender', 'sport'), field_filter('sport', *('Basketball', 'volleyball')),
    field_filter('gender', *('male'))

print(result):
[{'gender': 'male', 'name': 'Sam', 'sport': 'Basketball'}]

Мой код:

from typing import Dict, Any, Callable, Iterable

DataType = Iterable[Dict[str, Any]]
ModifierFunc = Callable[[DataType], DataType]

def query(data: DataType, selector: ModifierFunc,
          *filters: ModifierFunc) -> DataType:
    pass

def select(*columns: str) -> ModifierFunc:
    keys = [columns]
    res = []
    for dict1 in field_filter():
        result = dict((k, dict1[k]) for k in keys if k in dict1)
        res.append(result)
    return res

def field_filter(column: str, *values: Any) -> ModifierFunc:
    x = []
    for i in range(0, len(DataType)):
        y = DataType[i]
        if y[column] == values:
            x.append(y)
    return x

Не имел до этой задачи опыта с использованием функций в качестве аргумента иной функции. Предположил, что каждая функция должна в результате вернуть откорректированный list, и следующая уже будет корректировать результирующий list и т.д. Но IDE подсказывает, что ожидается, что результатом функций должен быть не тип данных list, а Iterable[Dict[str, Any]]. В общем и целом, я запутался. Аргументы функций задан


Ответы (1 шт):

Автор решения: splash58

Можно примерно так. С аннотациями разбирайтесь сами. Обратите внимание на вызовы, у вас там кортежи теряются - если он из одного элемента, над запятую ставить. И что-то еще было, забыл

def query(data: list[dict], selector: callable(list),
          *filters) -> list[dict]:
    res = []
    for x in data:
        if all(y(x) for y in filters):
            d = selector(x)
            res.append(d)
    return res


def select(*columns: str) -> callable:
    keys = [*columns]
    def selector(data):
        return {k: data[k] for k in keys if k in data}
    return selector


def field_filter(column: str, *values:str) -> callable:
    def filters(x):
        return column in x and x[column] in values
    return filters

friends = [
    {'name': 'Sam', 'gender': 'male', 'sport': 'Basketball'},
    {'name': 'Emily', 'gender': 'female', 'sport': 'volleyball'},
]
result = query(
    friends,
    select('name', 'gender', 'sport'), 
    field_filter('sport', *('Basketball', 'volleyball')),
    field_filter('gender', *('male',)))

print(result)
# [{'gender': 'male', 'name': 'Sam', 'sport': 'Basketball'}]

Или так, чтоб вызов фильтра был более читабельным

def query(data: list[dict], selector: callable(list),
          filter) -> list[dict]:
    res = []
    for x in data:
        if filter(x):
            d = selector(x)
            res.append(d)
    return res


def select(*columns: str) -> callable:
    keys = [*columns]
    def selector(data):
        return {k: data[k] for k in keys if k in data}
    return selector


def field_filter(**kwarg) -> callable:
    def filters(x):
        for k, v in kwarg.items():
            if not(k in x and x[k] in v):
                return False
        return True
    return filters


friends = [
    {'name': 'Sam', 'gender': 'male', 'sport': 'Basketball'},
    {'name': 'Emily', 'gender': 'female', 'sport': 'volleyball'},
]
result = query(
    friends,
    select('name', 'sport'),
    field_filter(sport=('Basketball', 'volleyball'), gender=('male',))
)
print(result)
→ Ссылка