Форум сайта python.su
Есть структура данных:
[
{’name’: ‘Foo’, ‘size’: 2, ‘count’: 1}
{’name’: ‘Bar’, ‘size’: 1, ‘count’: 3}
{’name’: ‘Bar’, ‘size’: 1, ‘count’: 2}
]
На выходе должно получиться:
[
{’name’: ‘Foo’, ‘size’: 2, ‘count’: 1}
{’name’: ‘Bar’, ‘size’: 1, ‘count’: 5}
]
Как сделать это на Python?
Понимаю, что в Django ORM это сделать просто, на у меня сложная вычисляемая структура данных и, кажется, проще это обработать оперативке, тем более список не особо большой. В голову приходит reduce, но не понимаю как там можно использовать составные ключи, также на уме библиотека для работы со структурами данных, но особо с ней не работал. Ключей в реальной задаче больше, чем 2, и суммируемых полей тоже.
Офлайн
Добавил ещё поле одно.
>>> def get_uniq_fields(lst, field_name): ... return tuple({i[field_name]:None for i in lst}) ... >>> def combine_fields(lst, field_name): ... return sum(i[field_name] for i in lst) ... >>> def join_objects(lst): ... out = [] ... names = get_uniq_fields(lst, 'name') ... for name in names: ... filtered_by_name = tuple(i for i in lst if i['name'] == name) ... template = filtered_by_name[0] ... count_combined = combine_fields(filtered_by_name, 'count') ... some_combined = combine_fields(filtered_by_name, 'some') ... template['count'] = count_combined ... template['some'] = some_combined ... out.append(template) ... return out ... >>> lst = [{'name': 'Foo', 'size': 2, 'count': 1, 'some': 10}, ... {'name': 'Bar', 'size': 1, 'count': 3, 'some': 20}, ... {'name': 'Bar', 'size': 1, 'count': 2, 'some': 30}] >>> >>> out = join_objects(lst) >>> out [{'name': 'Foo', 'size': 2, 'count': 1, 'some': 10}, {'name': 'Bar', 'size': 1, 'count': 5, 'some': 50}] >>>
Отредактировано py.user.next (Авг. 11, 2022 02:48:15)
Офлайн
from typing import Dict, Tuple, Generator class Summarizer: fields_to_sum = ["count"] unique_fields = ["name", "size"] def __init__(self): self._result: Dict[Tuple[str, ...], Tuple[int, ...]] = {} def add(self, record: Dict): uniques = tuple(record[i] for i in self.unique_fields) sums = tuple(record[i] for i in self.fields_to_sum) if sub_sums := self._result.get(uniques): sums = tuple(sum(i) for i in zip(sums, sub_sums)) self._result[uniques] = sums @property def result(self) -> Generator[Dict, None, None]: for uniques, sums in self._result.items(): _u = {k: v for k, v in zip(self.unique_fields, uniques)} _s = {k: v for k, v in zip(self.fields_to_sum, sums)} yield {**_u, **_s} summarizer = Summarizer() l = [{"name": "Foo", "size": 2, "count": 1}, {"name": "Bar", "size": 1, "count": 3}, {"name": "Bar", "size": 1, "count": 2} ] for i in l: summarizer.add(i) print(list(summarizer.result))
Отредактировано FishHook (Авг. 11, 2022 11:09:31)
Офлайн
lst = [ {'name': 'Foo', 'size': 2, 'count': 1}, {'name': 'Bar', 'size': 1, 'count': 3}, {'name': 'Bar', 'size': 1, 'count': 2} ] new_dict = {} for d in lst: k = (d['name'], d['size']) new_dict.setdefault(k, 0) new_dict[k] += d['count'] out = [{'name': k[0], 'size': k[1], 'count': v} for k, v in new_dict.items()] print(out)
[{'name': 'Foo', 'size': 2, 'count': 1}, {'name': 'Bar', 'size': 1, 'count': 5}]
Офлайн
xam1816
diagonМы не знаем насколько больше, можем предположить, что ключей десятки. Ваше решение имеет право на жизнь, вопросов нет, но мне кажется что в данном случае задачу надо решать в общем виде. Мне кажется хорошим критерием считать, что если мы изменим структуру данных добавив/удалив поле, то лучшее решение то, которое не влечет за собой никаких изменений кроме декларативных, слабее - если нам придется изменять алгоритм. Хотя, конечно, этим можно пожертвовать ради простоты и/или производительности.
Ключей в реальной задаче больше, чем 2, и суммируемых полей тоже.
Офлайн
Всем спасибо большое за интересные предложения.
Вспомнил еще про pandas
import pandas as pd data = [ {'name': 'Foo', 'size': 2, 'count': 1}, {'name': 'Bar', 'size': 1, 'count': 3}, {'name': 'Bar', 'size': 1, 'count': 2} ] df = pandas.DataFrame(data) out = df.groupby(['name', 'size'], as_index=False).sum('count').to_dict('records') print(print)
[ {'name': 'Bar', 'size': 1, 'count': 5}, {'name': 'Foo', 'size': 2, 'count': 1} ]
Офлайн
diagonМне кажется, тут все очень индивидуально и зависит от конкретной задачи, объема данных, их структуры, структуры команды и т.д. Несколько соображений:
Интересно услышать рассуждения других по поводу подобных задач.
Офлайн