Dropping n consecutive terms from a list periodically

The simplest (and probably fastest) way is to use Partition with the appropriate offset:

list = Range@100;
Flatten@Partition[list, 3, 5]
(* {1, 2, 3, 6, 7, 8, 11, 12, 13, 16, 17, 18, 21, 22, 23, 26, 27, 28, 
    31, 32, 33, 36, 37, 38, 41, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 
    58, 61, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 81, 82, 83, 86, 
    87, 88, 91, 92, 93, 96, 97, 98} *)

The logic is: "Take 3, drop 2, take 3, drop 2,... " till the end of the list (the argument 5 is just 3+2). You can change these numbers as desired.


I am rather amused that my f2 is considerably faster than Partition (here as f1).

Now with an additional method I'll name f4.

Third try. I'll name this function f5. It is optimized for short take sequences and it is quite fast in its element. It is in a way based on your original method.

f1[list_, take_, skip_] := Flatten @ Partition[list, take, take + skip, 1, {}]

f2[list_, take_, skip_] := 
  list[[ SparseArray[PadRight[#, Length@list, #] & @ 
   UnitStep @ Range[take - 1, -skip, -1]]["AdjacencyLists"] ]]

f4[list_, take_, skip_] := list ~Part~ With[{n = Length@list, m = take + skip},
   Drop[Tuples[{Range[0, n, m], Range[take]}] ~Total~ {2}, Min[0, Mod[n, m] - take]]
  ]

f5[list_, take_, skip_] := 
  list ~Part~ Flatten[Range[Range@take, Length@list, take + skip], {2, 1}]

Test:

a = RandomInteger[99, 1*^6];

First @ Timing @ Do[#[a, 3, 2], {100}] & /@ {f1, f2, f4, f5}

SameQ @@ (#[a, 3, 2] & /@ {f1, f2, f4, f5})
{3.962, 0.983, 0.952, 0.702}

True

Timings in version 10.1, including the Pick variation of f2 that rcollyer posted as f3 which only became practical in Mathematica 8.

Needs["GeneralUtilities`"]

BenchmarkPlot[
  Cases[{f1, f2, f3, f4, f5}, f_ :> (f[#, 3, 2] &)],
  RandomInteger[99, #] &,
  5
]

enter image description here

The same benchmark with (f[#, 88, 7] &):

enter image description here

And finally (f[#, 7, 88] &):

enter image description here


This is around six to nine times slower than @rm-rf 's :) But you can use it for more complicated patterns:

pickpat[a_List, pattern_List: {1, 1, 1, 0, 0}] := 
    Module[{patarray},
      patarray = Flatten@ConstantArray[pattern, Ceiling[Length@a/Length@pattern]];
      Pick[a, patarray[[1 ;; Length@a]], 1]
           ]

so

pickpat[Range@100]

 (*{1, 2, 3, 6, 7, 8, 11, 12, 13, 16, 17, 18, 21, 22, 23, 26, 27, 28,
31, 32, 33, 36, 37, 38, 41, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57,
58, 61, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 81, 82, 83, 86,
87, 88, 91, 92, 93, 96, 97, 98}*)

but, say if you wanted to drop the 2nd, 4th, 5th and 7th elements of a list you could call it like this:

pickpat[Range@100, {1,0,1,0,0,1,0}]

(*{1, 3, 6, 8, 10, 13, 15, 17, 20, 22, 24, 27, 29, 31, 34, 36, 38, 41,
43, 45, 48, 50, 52, 55, 57, 59, 62, 64, 66, 69, 71, 73, 76, 78, 80,
83, 85, 87, 90, 92, 94, 97, 99}*)