9
$\begingroup$

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[100]], 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?

$\endgroup$
3
  • 1
    $\begingroup$ expr = Range[20]; expr[[3 ;; ;; 3]] = 3;expr $\endgroup$
    – march
    Mar 25, 2016 at 18:19
  • $\begingroup$ @march was about to write that... $\endgroup$ Mar 25, 2016 at 18:21
  • $\begingroup$ expr = 4 Range[20]; expr[[Range[1, 20, 4]]] = Range[1, 20, 4]; expr :))) $\endgroup$
    – garej
    Mar 25, 2016 at 22:02

5 Answers 5

8
$\begingroup$

If you're okay with modifying the saved expression:

expr = Range[10]
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[10];
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[10]^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}]]
$\endgroup$
3
  • $\begingroup$ Interesting Part specification for MapAt. Documented? $\endgroup$
    – unlikely
    Mar 25, 2016 at 18:31
  • $\begingroup$ @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." $\endgroup$
    – march
    Mar 25, 2016 at 18:32
  • 1
    $\begingroup$ @march, here is another option: # /. Thread[Take[#, {3, -1, 3}] -> 3] &@Range[10] $\endgroup$
    – garej
    Mar 25, 2016 at 19:12
3
$\begingroup$
  If[Mod[#, 3] == 0, 3, EulerPhi[#]] & /@ Range[10]
  If[Mod[#, 4] == 1, #, 4 #] & /@ Range[10]
$\endgroup$
3
$\begingroup$

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.

$\endgroup$
1
3
$\begingroup$

Riffle version (relatively fast, by the way):

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

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


For the second part, using @march:

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

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

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

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}]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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