Переставить номера страниц - последующие


Это последующие: переставить номера страниц для печати книги

Вход:

  • Общее количество страниц книги: int
  • Страниц в буклете: int (делится на 4 нацело)

Обработка:

Перестановка страниц в каждой брошюре следовать определенному формату, [п, ф, ф+1, п-1], где N-последняя страница буклета, и F является первым.

Выход:

Печать списка/кортежа переставить числа

Ошибки:

Если страниц не кратно 4 последние брошюры (список, будут обработаны arrange_booklet()) всегда имеются ошибки в конце.

Разное:

инт страницах, как правило, будет большое количество (50~500). Я написал программу, потому что мое программное обеспечение принтера не позволяет мне просто печать страницы в таком порядке. Я должен вручную ввести все целое, разделенных запятыми. Что, несомненно, надоедает очень быстро.

from math import ceil


# f is the first page (smallest input integer), n is the last (largest)
def arrange_booklet(f, n):
    '''Creates a list by using the page # order formula.'''
    _ = list()
    while n > f:
        _.extend([n, f, f+1, n-1])
        f += 2
        n -= 2
    return _


def make_book():
    '''Combines all the lists into one and returns the result.'''
    pages = list(range(1, int(input("Enter a number of pages: "))+1))
    while True:
        len_booklet = int(input(
            "Enter booklet length, must be a multiple of four: "))
        if len_booklet % 4 == 0:
            break
    book = list()  # permanent list, to be returned
    _ = list()  # temporary list, to populate permanent list
    for page in pages:
        _.append(page)
        if page % len_booklet == 0:
            _ = arrange_booklet(_[0], _[-1])
            book.extend(_)
            _.clear()
    # the last booklet, if pages % 4 != 0, is still in the temp list and broke
    # out of the loop it has to be handled separately below, or it will never
    # reach the book
    if _:
        _ = arrange_booklet(_[0], _[-1])
        book.extend(_)
    print(book)


if __name__ == '__main__':
    make_book()


129
1
задан 13 апреля 2018 в 03:04 Источник Поделиться
Комментарии
2 ответа

Функции

нужно разбить много мелких кусков кода в отдельные функции, например, получение и разбор входных данных имеет место в make_book

Генераторы

Вместо того, чтобы использовать временные списки, используя генераторы намного чище.

поэтому вместо того, чтобы

def my_func():
_ = []
for i in range(10):
_.append(i**2)
return _

с генератором это становится:

def my_gen():
for i in range(10):
yield i**2

Это намного чище и легче поддерживать.

Сборка буклета

вместо перебора индексов f и nвы можете использовать collections.dequeи использовать pop и popleft

from collections import deque
def assemble_booklet(pages):
"""assembles the booklet according to the order [-1, 0, 1, -2] and going in.

Assumes an iterable with the length a multiple of 4"""
pages = deque(pages)
assert not len(pages) % 4, 'booklet length, must be a multiple of 4'
while pages:
selection = pages.pop(), pages.popleft(), pages.popleft(), pages.pop()
yield from selection

опять же, стиль генератор позволяет нам выразить это намного понятнее, чем через посредника списки

группировка на страницах

группировка страниц может быть легко сделано с grouper модуле itertools рецепт

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
"""Collect data into fixed-length chunks or blocks

grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
https://docs.python.org/3/library/itertools.html#itertools-recipes
"""
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)

Затем:

for page in pages:
_.append(page)
if page % len_booklet == 0:
_ = arrange_booklet(_[0], _[-1])
book.extend(_)
_.clear()

становится:

def make_book(pages, booklet_length):
'''Combines all the lists into one and returns the result.'''
assert not booklet_length % 4, 'booklet length, must be a multiple of 4'
for group in grouper(pages, booklet_length, fillvalue='blank'):
yield tuple(assemble_booklet(group))
# yield from assemble_booklet(group) # dependent on the output you want

Если вы хотите, чтобы страницы в 1 длинный список, а не разделены на буклет, вы можете изменить последнюю строку make_book для yield from assemble_booklet(group)

И по сути, это весь код для этого метода, который возвращает итерируемый страниц, и форма буклетов из них

if __name__ == '__main__':
pages = range(1, 16)
booklet_length = 8
result = list(make_book(pages, booklet_length))
print(result)


[(8, 1, 2, 7, 6, 3, 4, 5), ('blank', 9, 10, 15, 14, 11, 12, 13)]

3
ответ дан 13 апреля 2018 в 02:04 Источник Поделиться

@Josay это лучшее, что я могу получить код, чтобы быть. Если я по-прежнему игнорируется вашего главного вопроса, то я не понимаю, что ваш главный пункт-это, пожалуйста, поясните.

Память:

Я чувствую себя как функция arrange_booklet использует гораздо больше памяти, чем необходимо.

Ошибки:

Я думаю, что мне, наконец, удалось выяснить ошибка, когда появляются лишние значения в конце, если страниц не кратно len_booklet

Изменения:


  • Добавлено test() функция, которая подтверждает, если книга правильная длина

  • Удалены материалы от функции

  • Переехал какой-то код от старой make_book() функции и пересмотрел его, создал
    независимые функции grouper()

  • В сочетании что остальные arrange_booklet() и make_book() в новый
    arranged_booklet()

  • Входы позади if __name__ == '__main__' охранник

import itertools
import random

def grouper(pages, len_booklet, fillvalue=None):
'''pages is an iterable, len_booklet is an int
Creates "groups" of len_booklet length out of pages.'''
args = [iter(pages)] * len_booklet
result = list(itertools.zip_longest(*args, fillvalue=fillvalue))
for group in result:
yield list(group)

def arrange_booklet(grouped_book, len_booklet):
'''grouped book is an list, len_booklet is an in
Arranges grouped_book into the proper format.'''
for booklet in grouped_book:
while None in booklet:
booklet.remove(None)
n = booklet[-1]
f = booklet[0]
# beginning of special case
if len(booklet) <= len_booklet:
while len(booklet) > 4:
yield [n, f, f+1, n-1]
booklet = booklet[2:-2]
f += 2
n -= 2
if f == n:
yield [f]
elif f == n-1:
yield [n, f]
elif f == n-2:
yield [n, f, f+1]
else:
yield [n, f, f+1, n-1]
# end of special case
else:
while n > f:
yield [n, f, f+1, n-1]
f += 2
n -= 2

def test():
for i in range(100):
len_booklet = random.randrange(4, 256, 4)
pages = range(1, random.randint(4, 400))
while pages[-1] < len_booklet:
pages = range(1, random.randint(4, 400))
booklets = list(grouper(pages, len_booklet))
arranged_booklets = list(arrange_booklet(booklets, len_booklet))
book = list(itertools.chain.from_iterable(arranged_booklets))
print("pages : {}\nlen_booklet : {}\n".format(len(pages), len_booklet)
, end='')
if len(book) != len(pages):
print("Error!!!\n", len(book), len(pages))
break
else:
print("All's good\n")

if __name__ == '__main__':
test_or_main = input("Do you want to run a test? (y/n)")
if test_or_main == "n":
print("Running main program...")
pages = range(1, int(input("Enter a number of pages: "))+1)
while True:
len_booklet = int(input(
"Enter booklet length, must be a multiple of four: "))
if len_booklet % 4 == 0 and len_booklet <= len(pages):
break
booklets = list(grouper(pages, len_booklet))
arranged_booklets = list(arrange_booklet(booklets, len_booklet))
book = list(itertools.chain.from_iterable(arranged_booklets))
print(book)
else:
print("Running a test...")
test()

0
ответ дан 14 апреля 2018 в 08:04 Источник Поделиться