Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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]},
   Partition[PadRight[PadLeft[list, n + r1], n + r1 + r2], r, 1]
  ]

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.

share|improve this question
add comment

3 Answers 3

up vote 7 down vote accepted

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]}}
share|improve this answer
add comment

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]
share|improve this answer
add comment

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

share|improve this answer
1  
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 May 12 '13 at 22:49
    
@rm-rf A valid criticism. I'll try to improve this answer later. –  Mr.Wizard May 13 '13 at 3:39
    
@rm-rf I added a new section. –  Mr.Wizard May 13 '13 at 6:16
    
Thanks, voted :) –  rm -rf May 13 '13 at 14:17
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.