from collections import defaultdict
from pprint import pprint
all_templates = ['fitting_file_expdisk_cutout-IMG-HSC-I-18115-6,3-OBJ-NEP175857.9+655841.2.feedme', 'fitting_file_sersic_cutout-IMG-HSC-I-18115-3,3-OBJ-NEP180508.6+655617.3.feedme', 'fitting_file_sersic_cutout-IMG-HSC-I-18115-1,8-OBJ-NEP180840.8+665226.2.feedme', 'fitting_file_sersic_cutout-IMG-HSC-I-18115-6,7-OBJ-NEP175927.6+664230.2.feedme', 'fitting_file_expdisk_cutout-IMG-HSC-I-18114-0,5-OBJ-zsel56238.feedme', 'fitting_file_devauc_cutout-IMG-HSC-I-18114-0,3-OBJ-NEP175616.1+660601.5.feedme', 'fitting_file_sersic_cutout-IMG-HSC-I-18115-6,4-OBJ-zsel56238.feedme']
# simple helper function to extract the common object name
# you could probably use Regex... but then you'd have 2 problems
def objectName(path):
start = path.index('-OBJ-')
stop = path.index('.feedme')
return path[(start + 5):stop]
# I really wanted to use a one line reduce here, but...
grouped = defaultdict(list)
for each in all_templates:
grouped[objectName(each)].append(each)
pprint(grouped)
ASIDE / TANGENT
ОК, меня по-настоящему беспокоит то, что я не могу сделать простой вкладыш, используя reduce
. В конечном счете, я бы хотел, чтобы у python была хорошая groupby
функция. У него есть функция с таким именем, но она ограничена последовательными клавишами. Smalltalk, Objc и Swift имеют групповые механизмы, которые, в основном, позволяют объединять в кавычки произвольную передаточную функцию.
Моя первоначальная попытка выглядела так:
grouped = reduce(
lambda accum, each: accum[objectName(each)].append(each),
all_templates,
defaultdict(list))
Проблема в лямбде. Лямбда ограничена одним выражением. И для того, чтобы он работал в редукторе, он в большинстве случаев возвращает измененную версию накопленного аргумента. Но python не любит возвращать вещи из функций / методов, если это не нужно. Даже если мы заменим append
на <accessTheCurrentList> + [each]
, нам потребуется метод изменения словаря, который обновит значение ключа и вернет измененный словарь. Я не мог найти такую вещь.
Однако мы можем загрузить больше информации в наш аккумулятор, например, в кортеж. Мы можем использовать один слот кортежа для продолжения передачи указателя defaultdict, а другой - для получения бесполезного возврата None операции модификации. Это заканчивается довольно уродливо, но это один вкладыш:
from functools import reduce
grouped = reduce(
lambda accum, each: (accum[0], accum[0][objectName(each)].append(each)),
all_templates,
(defaultdict(list), None))[0]