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$
  • 1
    $\begingroup$ expr = Range[20]; expr[[3 ;; ;; 3]] = 3;expr $\endgroup$ – march Mar 25 '16 at 18:19
  • $\begingroup$ @march was about to write that... $\endgroup$ – Sjoerd C. de Vries Mar 25 '16 at 18:21
  • $\begingroup$ expr = 4 Range[20]; expr[[Range[1, 20, 4]]] = Range[1, 20, 4]; expr :))) $\endgroup$ – garej Mar 25 '16 at 22:02
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$
  • $\begingroup$ Interesting Part specification for MapAt. Documented? $\endgroup$ – unlikely Mar 25 '16 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 '16 at 18:32
  • 1
    $\begingroup$ @march, here is another option: # /. Thread[Take[#, {3, -1, 3}] -> 3] &@Range[10] $\endgroup$ – garej Mar 25 '16 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$
  • $\begingroup$ You could've used Divisible[n, 3] for the test. $\endgroup$ – J. M. is away Mar 26 '16 at 0:47
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$
  • 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 '16 at 5:05
  • $\begingroup$ @march, wow, I've missed such extension of Riffle, thanks for the tip... $\endgroup$ – garej Mar 28 '16 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.