2
$\begingroup$

I am new to Mathematica and I have no idea how to make a basic for loop work. I want to loop through the elements of a list: Range[45, 200]. I want to select the elements (i) for which the following conditions holds: if i mod 3 and i mod 8 and i mod 12 == 1 and i mod 5 == 0 I want to print the element. How would I achieve this? I want something like this:

for i in range(45, 201):
   if i%3==1 and i%8==1 and i%12==1 and i%5==0:
      print i

Of course in Mathematica language. Sorry if this is a dumb question but the Mathematica documentation is pretty hard to understand. Thanks.

$\endgroup$
6
  • 1
    $\begingroup$ "the mathematica documentation is pretty hard to understand." — Which part of the documentation for For did you try to use for your problem and where did you get stuck? $\endgroup$
    – rm -rf
    Feb 24, 2013 at 21:59
  • $\begingroup$ Possible duplicate: mathematica.stackexchange.com/q/7924/5 $\endgroup$
    – rm -rf
    Feb 24, 2013 at 22:00
  • 2
    $\begingroup$ Welcome to Mathematica.SE, user6078! As s0rce correctly points out, you don't need a loop here. Successful Mathematica programming requires you to get out of the loop-oriented mode of thinking. This earlier post might be helpful. $\endgroup$
    – Verbeia
    Feb 24, 2013 at 22:05
  • 1
    $\begingroup$ @rm-rf - related, but none of the answers there actually talk about Select and Cases. $\endgroup$
    – Verbeia
    Feb 24, 2013 at 22:07
  • $\begingroup$ @rm-rf - I understand the documentation, but implementing what I learned with other built-in functions is what I find hard, in this case I couldn't make the For, Range, and If functions work together. I even managed to put a little program together using pure logic, but the output was wrong. $\endgroup$
    – edferda
    Feb 25, 2013 at 2:36

5 Answers 5

9
$\begingroup$

You don't need to loop through the elements. Have a look at Select:

Select[Range[45, 200],Mod[#, 3] == Mod[#, 8] == Mod[#, 12] == 1 && Mod[#, 5] == 0 &]

(*

145

*)
$\endgroup$
3
  • $\begingroup$ Hope you don't mind, @s0rce, but I just added a bit from the answer I was about to post, to make it clear that loops are not needed in this case. $\endgroup$
    – Verbeia
    Feb 24, 2013 at 22:03
  • $\begingroup$ Thanks, I've read a little bit and it seems For loops are not appreciated much in Mathematica. From now on I will try to avoid them, it will be a problem since most programming languages rely so heavily on them. $\endgroup$
    – edferda
    Feb 25, 2013 at 2:43
  • 1
    $\begingroup$ You might like to review this question about loops and mathematica for more discussion on this topic. mathematica.stackexchange.com/questions/7924/… $\endgroup$ Feb 25, 2013 at 9:53
6
$\begingroup$

If you only want to print the result :

  If[
   Mod[#, 3] == Mod[#, 8] == Mod[#, 12] == 1 && Mod[#, 5] == 0, 
   Print[#]
   ] & /@ Range[45, 200];

the same code without the /@ which may be mysterious for beginners :

Map[
  If[
    Mod[#, 3] == Mod[#, 8] == Mod[#, 12] == 1 && Mod[#, 5] == 0, 
    Print[#]
    ] & ,
   Range[45, 200]
  ];

"only print the result" means.. that you can' t affect the result to a variable.

If you want to affect a variable see sOrce' s answer and add variable = at the beginning of his code

$\endgroup$
4
$\begingroup$

Defining a selector function sF:

  sF = Mod[#, 3] == Mod[#, 8] == Mod[#, 12] == 1 && Mod[#, 5] == 0 &;

you can use any of the following functions to select the elements of Range[45,200] that satisfy the criteria coded in sF:

  Select[#, sF] &@Range[45, 200] (*as in @sOrce's answer *)
  Pick[#, sF /@ #] &[Range[45, 200]]
  Cases[#, x_ /; sF[x]] &@Range[45, 200]
  Cases[#, x_?sF] &@Range[45, 200]  (* thanks: @m_goldberg *)
  # /. (x_ /; ! sF[x] :> (## &[])) & /@ Range[45, 200] (* thanks: Mr.Wizard *)
  If[sF[#], #, ## &[]] & /@ Range[45, 200] (* a variant of @andre's answer *)
  #[[SparseArray[Boole /@ sF /@ #]["NonzeroPositions"][[1]]]] &[Range[45, 200]]
  (* 145 *)

(Related Q/A:1)

$\endgroup$
2
  • 1
    $\begingroup$ This is a excellent answer, but here is a minor improvement: Cases[#, x_?(sF[#] &)] & can be simplified to Cases[#, _?sF] &. $\endgroup$
    – m_goldberg
    Feb 25, 2013 at 13:45
  • $\begingroup$ @m_goldberg, very nice, thank you; updated with your suggestion. $\endgroup$
    – kglr
    Feb 25, 2013 at 13:54
1
$\begingroup$

Using Sow/Reap and Scan:

Scan[If[Mod[#, 3] == 1 && Mod[#, 8] == 1 && Mod[#, 12] == 1 && 
       Mod[#, 5] == 0, Sow[#], Nothing] &, Range[45, 201]] // Reap // 
  Last // First

{145}


Using FoldList:

In order to get more observability, let's use FoldList and apply the criteria one by one:

FoldList[
  Cases[#1, #2] &
  , Range[45, 201] , {
   _?(Mod[#, 3] == 1 &)
   , _?(Mod[#, 8] == 1 &)
   , _?(Mod[#, 12] == 1 &)
   , _?(Divisible[#, 5] &)
   }
  ] // Column

enter image description here


Using this result, the criteria that has the most effect can be promoted to improve performance.

$\endgroup$
1
$\begingroup$

You can use ChineseRemainder:

f[x_] := 
 ChineseRemainder[{1, 1, 1, 0}, {3, 8, 12, 5}] + LCM[3, 8, 12, 5] x
f[x] /. Solve[45 <= f[x] <= 200, x, Integers]

yields {145}

If you want to Select, Pick, Cases:

r = Range[45, 200];
crit = Mod[#, {3, 8, 12, 5}] == {1, 1, 1, 0} & /@ r;
Pick[r, crit]
Select[r, Mod[#, {3, 8, 12, 5}] == {1, 1, 1, 0} &]
Cases[r, _?(Mod[#, {3, 8, 12, 5}] == {1, 1, 1, 0} &)]

all yield {145}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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