Это мой исходный код, он работает так, как мне нужно:
import collections
import json
import yaml
file_list = [
{'path': '/path/to/file1', 'size': 100, 'time': '2022-02-15'},
{'path': '/path/to/file2', 'size': 200, 'time': '2022-02-13'},
{'path': '/path/to/file3', 'size': 300, 'time': '2022-02-12'},
{'path': '/path/to/file4', 'size': 200, 'time': '2022-02-11'},
{'path': '/path/to/file5', 'size': 100, 'time': '2022-02-1-'}]
new_dict = collections.defaultdict(list)
for file in file_list:
new_dict[file['size']].append(file['path'])
print(json.dumps(new_dict, indent=4, sort_keys=True))
Я обнаружил, что использование collections.defaultdict(list) помогает упростить код цикла, поэтому мне не нужно проверять, существует ли уже ключ перед добавлением в его список.
Обновлено:
Можно ли сделать этот код кратким, используя понимание словаря для создания new_dict? Коллекция collections.defaultdict(list) ловит меня.
Если ваш код работает без ошибок и дает правильный результат, вы получите лучшую обратную связь о производительности, стиле и технике, если разместите свой вопрос на Code Review StackExchange.
«Можно ли сделать этот код лучше, используя понимание словаря для создания new_dict»: Нет. Понимание словаря/списка предназначено для случаев, когда каждая итерация цикла добавляет элемент в словарь, который вы создаете, т.е. если вы сделали new_dict[key] = value в петля. В этом случае вы добавляете к (возможно) уже существующему значению, поэтому вы не можете преобразовать его в понимание dict.
Код, который использует понимание, не обязательно «лучше», чем код, который этого не делает.
Если defaultdict вызывает у вас недоумение, измените его на обычный словарь и убедитесь, что каждый new_dict[key] существует и является списком, прежде чем пытаться добавить к нему
Вопрос только в том, могу ли я использовать понимание словаря для создания нового словаря в одной строке.
Если по какой-то причине вы хотите избежать импорта defaultdict, это один из способов сделать это:
import json
file_list = [
{'path': '/path/to/file1', 'size': 100, 'time': '2022-02-15'},
{'path': '/path/to/file2', 'size': 200, 'time': '2022-02-13'},
{'path': '/path/to/file3', 'size': 300, 'time': '2022-02-12'},
{'path': '/path/to/file4', 'size': 200, 'time': '2022-02-11'},
{'path': '/path/to/file5', 'size': 100, 'time': '2022-02-1-'}]
new_dict = {}
for file in file_list:
new_dict[file['size']] = (files := new_dict.get(file['size'], []))
files.append(file['path'])
print(json.dumps(new_dict, indent=4, sort_keys=True))
И если вам не нравится постоянное переназначение этого списка на запись в словаре (мне не очень):
for file in file_list:
if file['size'] not in new_dict:
new_dict[file['size']] = []
new_dict[file['size']].append(file['path'])
(Обратите внимание, что глубина отступа по умолчанию для Python равна 4, вы сделаете другим и себе в будущем одолжение, приняв это раньше, чем позже)
Как указано в комментариях, возможно, более элегантное решение:
for file in file_list:
new_dict.setdefault(file['size'], []).append(file['path'])
Однако, несмотря на то, что можно придумать однострочное понимание, оно не будет более эффективным, быстрым или удобочитаемым. На самом деле, скорее всего, ни один из них - так какой в этом смысл?
Более короткий код часто является лучшим кодом, если он не ставит под угрозу функциональность или удобочитаемость, но никогда не должен быть целью сам по себе.
Например, рассмотрим этот (плохой) пример:
c_dict = {size: [fp['path'] for fp in file_list if fp['size'] == size] for size in set(fs['size'] for fs in file_list)}
И хотя это одна строка, вы, вероятно, захотите написать ее так для удобочитаемости, и в этот момент у вас просто будет больше кода, чем раньше:
c_dict = {
size: [fp['path'] for fp in file_list if fp['size'] == size]
for size in set(fs['size'] for fs in file_list)
}
Вопрос только в том, могу ли я использовать понимание словаря для создания нового словаря в одной строке.
files = new_dict.setdefault(file['size'], [])
— менее неуклюжий способ написания строки с помощью оператора «морж».
Внутри цикла for на самом деле может быть одна строка: new_dict.setdefault(file['size'], list()).append(file['path'])
@ quantum231 Нет, это нельзя решить с помощью понимания словаря для этого сценария, но вы можете избежать использования defaultdict, используя методы get() или setdefault() в обычном словаре.
Почему мы не можем сделать что-то вроде этого: new_dict = {k: v для файла в списке_файлов: setdefault(file['size'], []).append(file['path'])} Я относительно новичок в Python и время от времени пишу сценарии, чтобы облегчить себе работу.
Я не думаю, что есть смысл подробно объяснять, почему то, что вы предложили, не сработает (по разным причинам), но см. Ответ для примера понимания, выполняющего эту работу. Однако, если бы я вел курс Python, вы бы получили меньше баллов за этот ответ, чем за любой другой, поскольку он ни в чем не лучше.
Потому что это недопустимый синтаксис Python. setdefault() и get() — это методы dict, поэтому их нужно вызывать в экземпляре dict. Вы можете написать функцию генератора, которую вы могли бы перебирать, чтобы получить следующий размер файла и путь из списка файлов, и использовать это в своем понимании dict, но тогда вы на самом деле пишете больше кода.
@quantum «почему мы не можем сделать ...»: см. Мой комментарий к вашему вопросу выше, но хороший учебник по пониманию, вероятно, поможет вам лучше. Понимание используется, когда каждая итерация вашего цикла предоставляет одно значение (или пару ключ-значение) для построения списка или словаря.
Хорошо, я понимаю, что мое понимание было неполным
Не могу утверждать, что это более «кратко», но в конце концов это понимание слова: D
from itertools import groupby
from operator import itemgetter
sort_list = sorted(file_list, key=itemgetter('size'))
groups = groupby(sort_list, key=itemgetter('size'))
print({k:[i['path'] for i in g] for k, g in groups})
Просто убедитесь, что ваши данные связны.
file_list = [
{'path': '/path/to/file1', 'size': 100, 'time': '2022-02-15'},
{'path': '/path/to/file2', 'size': 200, 'time': '2022-02-13'},
{'path': '/path/to/file3', 'size': 300, 'time': '2022-02-12'},
{'path': '/path/to/file4', 'size': 200, 'time': '2022-02-11'},
{'path': '/path/to/file5', 'size': 100, 'time': '2022-02-1-'}]
new_dict = {key: [file_dict[key] for file_dict in file_list] for key in file_list[0].keys()}
Для краткости просто используйте DataFrame???
new_dict = pd.DataFrame(file_list).to_dict(orient='list')
Никогда раньше не сталкивался с фреймворком данных
Что значит "лучше"?