How can I use the overhang argument to Partition to avoid using PadLeft and PadRight here?

Say I have a list of values v = {v1, v2, v3, ... }. I need to partition these values to perform operations with a sliding window (think MovingAverage).

I define my window as {r1, r2} where r1 indicates the number of objects to capture to the left and r2 is the number to the right of each of the vi. Thus, my window width is r1 + r2 + 1.

I have written a function which does this partitioning.

f[list_, {r1_, r2_}] := With[{r = r1 + r2 + 1, n = Length[list]},
]


For example.

f[Array[v, 6], {1, 3}]

(*{{0, v[1], v[2], v[3], v[4]}, {v[1], v[2], v[3], v[4], v[5]}, {v[2],
v[3], v[4], v[5], v[6]}, {v[3], v[4], v[5], v[6], 0}, {v[4], v[5],
v[6], 0, 0}, {v[5], v[6], 0, 0, 0}}*)


Is there a way to use the overhang argument to Partition so that I can avoid PadLeft and PadRight?

The reason I don't just use this solution is because ultimately I don't want the zeros, I will be working with a ragged array. If I can get the overhang argument right I can just use {} for padding saving me from post processing the zeros.

Something like this?

f[list_, {r1_, r2_}, pad_] := Partition[list, r1 + r2 + 1, 1, {r1 + 1}, pad]

In[14]:= f[Array[v, 6], {1, 4}, 0]

Out[14]= {{0, v[1], v[2], v[3], v[4], v[5]}, {v[1], v[2], v[3], v[4],
v[5], v[6]}, {v[2], v[3], v[4], v[5], v[6], 0}, {v[3], v[4], v[5],
v[6], 0, 0}, {v[4], v[5], v[6], 0, 0, 0}, {v[5], v[6], 0, 0, 0, 0}}

In[15]:= f[Array[v, 6], {1, 4}, {}]

Out[15]= {{v[1], v[2], v[3], v[4], v[5]}, {v[1], v[2], v[3], v[4],
v[5], v[6]}, {v[2], v[3], v[4], v[5], v[6]}, {v[3], v[4], v[5],
v[6]}, {v[4], v[5], v[6]}, {v[5], v[6]}}


You can use values other than ±1 for the overhang arguments, although the "Details" section for Partition doesn't mention this. In your case, the following works:

Partition[Array[v, 6], 5, 1, {-4, 2}, {}]
(* {{v[1], v[2], v[3], v[4]}, {v[1], v[2], v[3], v[4], v[5]}, {v[2], v[3], v[4], v[5], v[6]},
{v[3], v[4], v[5], v[6]}, {v[4], v[5], v[6]}, {v[5], v[6]}} *)


More generally, the equivalent of your function can be written using only Partition as (with {r1, r2} being the window specs):

Partition[list, r1 + r2 + 1, 1, {-1 - r2, 1 + r1}, padding]


Your original function can be written much more concisely using ArrayPad:

f2[list_, p : {_, _}] := Partition[list ~ArrayPad~ p, Tr@p + 1, 1]

f2[Range@5, {1, 3}]


Also, since this question is tagged I would like to point out that using the zero-padding might be more efficient. A raw demonstration, using MinHsuan Peng's function to compare:

f[list_, {r1_, r2_}, pad_] := Partition[list, r1 + r2 + 1, 1, {r1 + 1}, pad]

r = RandomInteger[99, 15000];
p = {1, 3};

Do[f[r, p, {}], {1500}] // Timing // First
Do[f2[r, p], {1500}]    // Timing // First


1.576

0.639

Given that the zeros will only appear in a limited number (the values of r1 and r2) of entries at the beginning and end of the list it may be more efficient to handle these cases separately.

To give a more practical comparison this function returns the partitions in three sections. They are not joined at this time because that entails unpacking the list and greatly slows the process, but one could apply the post-function at this level and join the result (packing first if possible). Keeping all elements except the head and tail sections packed should allow for optimized application.

f3[list_, {r1_, r2_}] := With[{n = r1 + r2 + 1}, {
Array[Take[list, r2 + #] &, r1],
Partition[list, n, 1],
Array[Take[list, # - n] &, r2]
}]

f3[Range@9, {1, 3}] // Column

{{1, 2, 3, 4}}
{{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}, {4, 5, 6, 7, 8}, {5, 6, 7, 8, 9}}
{{6, 7, 8, 9}, {7, 8, 9}, {8, 9}}


Timings:

r = RandomInteger[99, 12000];
p = {2, 5};

Do[f[r, p, {}], {1500}] // Timing // First
Do[f3[r, p], {1500}]    // Timing // First


1.544

0.687

• But Andy explicitly says that he doesn't want to zero pad for other reasons — "The reason I don't just use this solution is because ultimately I don't want the zeros, I will be working with a ragged array. If I can get the overhang argument right I can just use {} for padding saving me from post processing the zeros." So if you're comparing performance with the other solutions, you should also account for whatever time (and additional code complexity) that post processing takes.
– rm -rf
Commented May 12, 2013 at 22:49
• @rm-rf A valid criticism. I'll try to improve this answer later. Commented May 13, 2013 at 3:39
• @rm-rf I added a new section. Commented May 13, 2013 at 6:16