Как создать несколько списков из одного списка в соответствии с соответствующими подстроками? - PullRequest
0 голосов
/ 24 января 2019

У меня есть список строк в Python, состоящий из различных имен файлов, как это (но гораздо дольше):

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

Я хотел бы создать несколько небольших списков для элементов с одинаковым именем объекта (подстрока, начинающаяся с OBJ- и заканчивающаяся прямо перед .feedme). Итак, у меня был бы такой список:

obj1 = ['fitting_file_expdisk_cutout-IMG-HSC-I-18114-0,5-OBJ-zsel56238.feedme', 'fitting_file_sersic_cutout-IMG-HSC-I-18115-6,4-OBJ-zsel56238.feedme']

и т. Д. Для других соответствующих «объектов». На самом деле у меня есть более 900 уникальных «объектов», а исходный список all_templates содержит более 4000 элементов, потому что у каждого объекта есть 3 или более отдельных файла шаблона (все они появляются в произвольном порядке для начала). В итоге я хочу иметь более 900 списков (по одному на объект). Как я могу это сделать?

Редактировать: вот что я попробовал, но он дает мне список ВСЕХ исходных имен файлов шаблонов внутри каждого подсписка (каждый из которых должен быть уникальным для одного имени объекта).

import re
# Break up list into multiple lists according to substring (object name)
obj_list = [re.search(r'.*(OBJ.+)\.feedme', filename)[1] for filename in all_template_files]
obj_list = list(set(obj_list)) # create list of unique objects (remove duplicates)

templates_objs_sorted = [[]]*len(obj_list)
for i in range(len(obj_list)):
    for template in all_template_files:
        if obj_list[i] in template:
            templates_objs_sorted[i].append(template)

Ответы [ 3 ]

0 голосов
/ 24 января 2019

Вы можете сгруппировать отсортированный список:

from itertools import groupby
import re

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

pattern = re.compile(r'OBJ-.*?\.feedme$')
objs = {name: pattern.search(name)[0] for name in all_templates}
result = [list(g) for k, g in groupby(sorted(all_templates, key=objs.get), key=objs.get)]

print(result)

Вывод:

[['fitting_file_devauc_cutout-IMG-HSC-I-18114-0,3-OBJ-NEP175616.1+660601.5.feedme'],
 ['fitting_file_expdisk_cutout-IMG-HSC-I-18115-6,3-OBJ-NEP175857.9+655841.2.feedme'],
 ['fitting_file_sersic_cutout-IMG-HSC-I-18115-6,7-OBJ-NEP175927.6+664230.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_expdisk_cutout-IMG-HSC-I-18114-0,5-OBJ-zsel56238.feedme',
  'fitting_file_sersic_cutout-IMG-HSC-I-18115-6,4-OBJ-zsel56238.feedme']]
0 голосов
/ 24 января 2019

Используя regular expression методы, поэтому требуется

import re

Учитывая список имен файлов, я настроил его для отображения результата:

all_templates = ['aaa-OBJ-NEP175857.9+655841.2.feedme',
                 'bbb-OBJ-NEP175857.9+655841.2.feedme',
                 'ccc-OBJ-NEP175857.9+655841.2.feedme',
                 'ddd-OBJ-whathever.feedme',
                 'eee-OBJ-whathever.feedme',
                 'fff-SUBJ-whathever.feedme',
                 'fff-OBJ.feedme'
                ]

Это может быть опция:

result = {}
for filename in all_templates:
  match = re.search('OBJ-(.+?).feedme', filename)
  if match:
    result.setdefault(match.group(1), list()).append(filename)
  else:
    result.setdefault('no-match', list()).append(filename)

Он использует подстроку между OBJ- и .feedme в качестве ключа dict, добавляя каждое имя файла с той же подстрокой.Если совпадения не найдено, он использует 'no-match' для добавления подстроки, не соответствующей поиску.

Итак, он возвращает:

print(result)
# {'NEP175857.9+655841.2': ['aaa-OBJ-NEP175857.9+655841.2.feedme', 'bbb-OBJ-NEP175857.9+655841.2.feedme', 'ccc-OBJ-NEP175857.9+655841.2.feedme'],
#  'whathever': ['ddd-OBJ-whathever.feedme', 'eee-OBJ-whathever.feedme'],
#  'no-match': ['fff-SUBJ-whathever.feedme', 'fff-OBJ.feedme']}

Если вам нужен только список групп:

list(result.values())
0 голосов
/ 24 января 2019
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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...