29

Is there some direct and simple "cyclic Take", sometimes also known as "overtake" in Mathematica. That is, if the take specification runs out of elements, it just cycles back to the beginning (as many times as necessary).

For example, if the functions were named OverTake, then:

OverTake[{1, 2}, 5]
(* {1, 2, 1, 2, 1} *)

(This would be a direct analog of the take functions in the array-processing languages APL and J.)

I can clumsily code a function to do that, but I was hoping for a simple use of something built in.

kglr
  • 394,356
  • 18
  • 477
  • 896
murray
  • 11,888
  • 2
  • 26
  • 50
  • 10
    Maybe PadRight[{}, 5, {1, 2}]? – Szabolcs Nov 11 '15 at 20:51
  • 1
    @Szabolcs That's brilliant! It also naturally handles the "normal" Take usage when requesting fewer elements than the length of the list. Please post it as an answer! – MarcoB Nov 11 '15 at 21:06
  • I'm waiting for @Szabolcs to post his comment as answer, since that's the one I'd like to mark (as the simplest). – murray Nov 11 '15 at 22:10
  • I guess you can accept kglr's :) – Szabolcs Nov 11 '15 at 22:17
  • 7
  • Then @Kuba's answer at the related/duplicate you cite ought to be the accepted answer! Any way to do that? (I'm not trying to be stinting in awarding credit to anybody!) – murray Nov 11 '15 at 22:34
  • murray, I think this q/a can be closed as duplicate of the linked q/a. I will delete my answer for it also appears in that q/a. But I don't know how to deal with new answers (like eldo's) that appear only in the current q/a -- perhaps @eldo can post his answer there but that would mean losing the votes when this q/a is eventually deleted as duplicate. – kglr Nov 11 '15 at 22:51
  • But it would be nice to preserve using the "Periodic" argument to PadRight. It will be once this is closed, right? – murray Nov 11 '15 at 22:56
  • murray, my answer in the linked q/a includes PadRight[...,"Periodic"]. – kglr Nov 11 '15 at 23:03
  • 1
    @kglr I'd like to join murray in asking you to consider undeleting your answer. Although you do reference using "Periodic" with PadRight in the other answer, I don't see why it shouldn't be preserved here as well. – MarcoB Nov 11 '15 at 23:04
  • @MarcoB, thank you for the suggestion. I undeleted the answer. – kglr Nov 11 '15 at 23:19
  • I don't mind preserving those answers, but I'd still close it as duplicate. – Kuba Nov 25 '15 at 12:18

3 Answers3

29

A variation on Szabolcs's suggestion:

overTake = PadRight[##, "Periodic"] &;
overTake[{1, 2}, 5]

{1, 2, 1, 2, 1}

kglr
  • 394,356
  • 18
  • 477
  • 896
  • 7
    Where did you lean about the "Periodic" argument to PadRight? I'm not seeing it at doc page ref/PadRight. – murray Nov 11 '15 at 21:52
  • See Details for ArrayPad – eldo Nov 11 '15 at 22:10
  • 10
    @murray, afaik, the fact that PadRight and PadLeft work with a third argument just like ArrayPad is undocumented. I found out by pure luck -- wishing PadRight worked like ArrayPad, tried it and saw it worked:) – kglr Nov 11 '15 at 22:28
14
Catenate @ Partition[{1, 2}, 5, 5, 1]

{1, 2, 1, 2, 1}

OverTake[list_, n_] /; Length @ list >= n := Take[list, n]

OverTake[list_, n_] /; Length @ list < n := Catenate @ Partition[list, n, n, 1]

OverTake[Range @ 5, 6]

{1, 2, 3, 4, 5, 1}

OverTake[Range @ 5, 4]

{1, 2, 3, 4}

Update

Faster than solutions with PadRight and Partition

l = 2;
n = 5;
list = Range @ l;

Flatten@ConstantArray[list, IntegerPart[n/l]]~Join~list[[;; Mod[n, l]]]

{1, 2, 1, 2, 1}

Also works for n < l

eldo
  • 67,911
  • 5
  • 60
  • 168
3

For historical reasons, let me mention the CycleValues function that originates before v6, and can be found in several standard packages. I copy the one from Packages\BarCharts\Charts.m with its description by the dev who included. (If you check however StatisticalPlots.m, it already uses the PadRight version.) Note, that it was meant to handle non-list arguments as well.

(* The following is a useful internal utility function to be
used when you have a list of values that need to be cycled to
some length (as PlotStyle works in assigning styles to lines
in a plot).  The list is the list of values to be cycled, the
integer is the number of elements you want in the final list. *)

CycleValues[{},_] := {}
CycleValues[list_List, n_Integer] := Module[{hold = list},
        While[Length[hold] < n,hold = Join[hold,hold]];
        Take[hold,n] /. None -> {}
    ]
CycleValues[item_,n_] := CycleValues[{item}, n];


CycleValues[0, 5]        (* ==> {0, 0, 0, 0, 0} *)
CycleValues[{1, 2}, 5]   (* ==> {1, 2, 1, 2, 1} *)
István Zachar
  • 47,032
  • 20
  • 143
  • 291