подстановка диапазона с заполненными нулями - python

Быстрый вопрос по поводу глобализации в python.

У меня есть каталог файлов «sync_0001.tif», «sync_0002.tif», ..., «sync_2400.tif». Я хотел бы получить 3 подмножества этих файлов: 1 для первых 800 файлов, вторые 800 файлов и последние 800 файлов. Единственная проблема - это 0 перед числами. Я не могу найти правильный способ получить эти списки. Третий список прост, потому что ни в одном из этих файлов нет заполнения нулями (s3 = glob.glob ('sync_ [1601-2400] .tif'). Два других более сложны, потому что количество нулей впереди меняется.

Я пробовал это, но получил 'плохой диапазон символов', я предполагаю из-за 0:

s1 = glob.glob('sync_' + '{[0001-0009], [0010-0099], [0100-0800]}' + '.tif')
s2 = glob.glob('sync_' + '{[0801-0999], [1000-1600]}' + '.tif')

Затем я попытался переместить 0 вперед, но получил пустой список:

s1 = glob.glob('sync_' + '{000[1-9], 00[10-99], 0[100-800]}' + '.tif')

Как лучше всего составить эти три списка? Я начинаю думать, что у меня все неправильно, так что, если бы кто-то мог пролить свет, это было бы здорово. Спасибо!


person user20408    schedule 07.04.2014    source источник
comment
fnmatch() синтаксис, используемый glob, недостаточно сложен ..   -  person Martijn Pieters    schedule 07.04.2014


Ответы (2)


fnmatch модуль, лежащий в основе функции glob.glob(), недостаточно сложен для вашей задачи.

Просто возьмите все имена файлов и разделите их после сортировки:

filenames = sorted(glob.glob('sync_[0-9][0-9][0-9][0-9].tif'))

Это работает, потому что ваши числа дополнены и, таким образом, могут быть отсортированы лексикографически. Затем разделите их:

s1 = [f for f in filenames if 0 < int(f[5:9]) <= 800]
s2 = [f for f in filenames if 800 < int(f[5:9]) <= 1600]
s3 = [f for f in filenames if 1600 < int(f[5:9]) <= 2400]

В любом случае ввод-вывод каталога будет самым медленным. Вы можете сделать все это немного более эффективным, выполнив цикл только один раз и поменяв местами то, что вы добавляете:

target = s1 = []
s2 = []
s3 = []
for f in filenames:
    num = int(f[5:9])
    if num > 800:
        target = s2
    elif num > 1600:
        target = s3
    target.append(f)

но для такой задачи вполне подойдет и более простое понимание списка.

person Martijn Pieters    schedule 07.04.2014
comment
Не все файлы sync_, некоторые - sync999, а другие sync 000; если только это не опечатка в исходном вопросе. - person Burhan Khalid; 07.04.2014
comment
@BurhanKhalid: в примерах попыток подстановки используется шаблон, который я использовал в своем ответе. Я предполагаю, что исключения - это опечатки. - person Martijn Pieters; 07.04.2014
comment
@BurhanKhalid да, извините. это была ошибка. спасибо вам обоим за ваши ответы! Я приму этот ответ, потому что он близок к моему исходному решению, и я могу сделать это всего за 3 строки - person user20408; 07.04.2014

Лучший способ сделать это просто:

  1. Убрать все файлы, которые начинаются с sync
  2. Сортировать список по числовой составляющей
  3. Разделите его на куски по 800

Поскольку вы уже знакомы с глобуляцией, остальное:

import glob
import re
from itertools import izip_longest

# https://docs.python.org/2/library/itertools.html#recipes
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)


def sorter(x):
    return int(re.search('(\d+)',x).groups()[0])

files = glob.glob('sync*.tif')
sorted_files = sorted(files, key=sorter)
in_batches = list(grouper(sorted_files, 800))

Поскольку шаблон всегда sync_ (после вашего редактирования), вы можете упростить приведенный выше код до следующего:

files = glob.glob('sync_*.tif')
sorted_files = sorted(files, key=lambda x: int(x.split('_')[1]))
in_batches = list(grouper(sorted_files, 800))
person Burhan Khalid    schedule 07.04.2014
comment
Спасибо. Это тоже жизнеспособное решение. Пытался проголосовать, но репутации не хватает. еще раз спасибо - person user20408; 07.04.2014