# What is the most efficient way to replace items in a list at periodic intervals?

For example, if I want a list of $\phi(n)$ for $1 \leq n \leq 100$ but if $n$ is a multiple of 3 I want to show a 3 instead of $\phi(n)$. I tried

ReplacePart[EulerPhi[Range], Table[{3n}, {n, 33}] -> 3]


but this just feels wrong.

Or a somewhat more involved example: show $4n$ except when $n \equiv 1 \pmod 4$, in which case show just $n$.

I am aware both of these can be accomplished with If. But there's a better way, isn't there?

• expr = Range; expr[[3 ;; ;; 3]] = 3;expr – march Mar 25 '16 at 18:19
• @march was about to write that... – Sjoerd C. de Vries Mar 25 '16 at 18:21
• expr = 4 Range; expr[[Range[1, 20, 4]]] = Range[1, 20, 4]; expr :))) – garej Mar 25 '16 at 22:02

## 5 Answers

If you're okay with modifying the saved expression:

expr = Range
expr[[3 ;; ;; 3]] = 3;
expr
(* {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} *)
(* {1, 2, 3, 4, 5, 3, 7, 8, 3, 10} *)


If you're not:

expr = Range;
MapAt[3 &, expr, {3 ;; ;; 3}]
(* {1, 2, 3, 4, 5, 3, 7, 8, 3, 10} *)


A modified version of OP's

ReplacePart[expr, List /@Range[3, Length@expr, 3] -> 3]


For the second example, a modified version of OP:

expr = Range^2
ReplacePart[expr, Thread[Range[1, 10, 4] -> Range[1, 10, 4]]]
(* {1, 4, 9, 16, 25, 36, 49, 64, 81, 100} *)
(* {1, 4, 9, 16, 5, 36, 49, 64, 9, 100} *)


and also

MapIndexed[If[Mod[First@#2, 4] == 1, First@#2, #1] &, expr]
Module[{i = -3}, MapAt[(i = i + 4) &, expr, {;; ;; 4}]]

• Interesting Part specification for MapAt. Documented? – unlikely Mar 25 '16 at 18:31
• @unlikely. I don't know. I learned that here! But there is this hint in the documentation: "MapAt works on Association objects, using the same specification for keys as in Part." – march Mar 25 '16 at 18:32
• @march, here is another option: # /. Thread[Take[#, {3, -1, 3}] -> 3] &@Range – garej Mar 25 '16 at 19:12
  If[Mod[#, 3] == 0, 3, EulerPhi[#]] & /@ Range
If[Mod[#, 4] == 1, #, 4 #] & /@ Range


You can use pattern also:

 ReplacePart[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, n_ /; IntegerQ[n/3] :> 3]


I did not understand the second part of your question so I did not post answer for that.

• You could've used Divisible[n, 3] for the test. – J. M.'s ennui Mar 26 '16 at 0:47

Riffle version (relatively fast, by the way):

Riffle[Drop[Range, {3, -1, 3}], 3, 3]


{1, 2, 3, 4, 5, 3, 7, 8, 3, 10}

For the second part, using @march:

expr = Range^2;
expr[[Range[1, 10, 4]]] = Range[1, 10, 4]; expr


{1, 4, 9, 16, 5, 36, 49, 64, 9, 100}

• The Riffle version is very fast! +1. Here's a Riffle for the second part: Riffle[Drop[Range^2, {1, -1, 4}], Range[1, 10, 4], {1, -1, 4}]. – march Mar 28 '16 at 5:05
• @march, wow, I've missed such extension of Riffle, thanks for the tip... – garej Mar 28 '16 at 6:00

This answer uses a function defined in my answer here. If you find the definition too complicated, also see Mr.Wizards answer.

This does not calculate EulerPhi more often than necessary.

Riffle[EulerPhi /@ nonMultsCondManMod[10, 3], 3, {3, -1, 3}]


For the more involved example

nn = 20;
mm = 4;
Riffle[mm (nonMultsCondManMod[nn, mm] + 1),
Range[1, nn, mm], {1, -mm, mm}]