1

I'm creating a workflow for booklet printing with 2 pages on an open spread:

  1. Use R to create the page sequence
  2. Use pdftk to repaginate the pdf
  3. Use lp to print the 2-up booklet

I've written a loop for repaginating pdfs for booklet/saddle stitch sequence. For an 8-pg booklet, the print sequence should be "8 1 2 7 6 3 4 5". I can create the sequence in the following loop but don't know how to output it into a single line with each page number separated with a space.

p <- 16  # number of pages in a saddle stitch, multiple of 4
p.seq <- c(1:p) # page sequence
p2 <- p/2

for (i in 1:p2) {
  ifelse(p.seq[i] %% 2 == 0, # true if even number
    print(paste(i, p - i + 1, sep=" ")),
    print(paste(p - i + 1, i, sep=" "))
    )
}   

Tried to use cat(..., append=TRUE) instead of print, but that stops the loop.

jay.sf
  • 60,139
  • 8
  • 53
  • 110
Rain
  • 13
  • 2
  • I should mention that the repagination came out as an intermediate step because `lp -o page-ranges=…` only accepts an ascending page sequence – Rain Feb 26 '23 at 21:59

1 Answers1

0

Try this

p <- 16
for (i in seq_len(p/2)) {
  if (i %% 2) cat(c(p - i + 1, i), '')
  else cat(c(i, p - i + 1), '')
}   
# 16 1 2 15 14 3 4 13 12 5 6 11 10 7 8 9 

If you want to be able to save the result (i.e. not just print/cated on the console), you could write a function f:

f <- \(p) unlist(lapply(seq_len(p/2), \(i) {
  if (i %% 2) c(p - i + 1, i)
  else c(i, p - i + 1)
}))

You could use it in a bash script then

#!/bin/bash
p=8

o=$(Rscript -e "
f <- \(p) unlist(lapply(seq_len(p/2), \(i) {
  if (i %% 2) c(p - i + 1, i)
  else c(i, p - i + 1)
}))
f($p)
")

echo $o  ## use in pdftk instead of echo

$ ./foo.sh
[1] 8 1 2 7 6 3 4 5

A more fail-safe version of the R function could be

f <- \(p) {
  if (is.na(p) || is.null(p)) NULL
  else if (p < 0 || p != round(p)) stop('p not a positive round number')
  else if (p == 1) 1
  else {
    unlist(lapply(seq_len(p/2), \(i) {
      if (i %% 2) c(p - i + 1, i)
      else c(i, p - i + 1)
    }))
  }
}
    
f(8)
# [1] 8 1 2 7 6 3 4 5

## `cat`ed
cat(f(8))
# 8 1 2 7 6 3 4 5

f(16)
# [1] 16  1  2 15 14  3  4 13 12  5  6 11 10  7  8  9

f(1)
# [1] 1

f(0); f(NA); f(NULL)
# NULL

f(-3.1); f(-1)
# Error in f(-3.1) : `p` not a positive round number

Alternatively, to store a for loop result, you could initialize a list res that you can unlist afterwards.

p <- 8
res <- vector(mode='list', length=p/2)
for (i in seq_len(p/2)) {
  if (i %% 2) res[[i]] <- c(p - i + 1, i)
  else res[[i]] <- c(i, p - i + 1)
}   
unlist(res)
# [1] 8 1 2 7 6 3 4 5

to cat it:

cat(unlist(res))
# 8 1 2 7 6 3 4 5
jay.sf
  • 60,139
  • 8
  • 53
  • 110
  • This is excellent! First answer was exactly what I needed. Second answer (the function and bash script) anticipates what I or anyone else can use in their workflow. Third answer(fail-safe R function) is a best-practise of robust coding. I'm too green to be able to cast an upvote, but thanks @jay.sf, this is as complete an answer as anyone could ask for. – Rain Feb 26 '23 at 22:00