2
$\begingroup$

I have a question about for loop. In this example i made For loop without function, like this

    list = RandomInteger[10, 20]
a = Length[list];
For[i = 1, i < a + 1, i++,
 If[list[[i]] >= 5, list[[i]] = list[[i]]^2, 
  list[[i]] = list[[i]]^0.5];
 Print["iteration ", i, ", " , list[[i]]]
 ]

the code is working corectly. But, when I put For loop inside the function like this

    list = RandomInteger[10, 10];
function[list_] := Module[{a = Length[list]},
  For[i = 1, i < a + 1 , i++, 
   If[list[[i]] >= 5, list[[i]] = list[[i]]^2, 
    list[[i]] = list[[i]]^0.5];
   Print["iteration ", i, ", ", list[[]]]
   ]
  ]
function[list]

than I get an error. Why is this happening. Is for loop suitable for functions?

$\endgroup$
2
  • 1
    $\begingroup$ The use of For-loops and friends is heavily discouraged in Mathematica. Have a look at Map, Apply, Fold,... instead. $\endgroup$
    – Sascha
    Apr 14, 2018 at 11:46
  • $\begingroup$ Speaking figuratively, >90% probability, NO. $\endgroup$ Apr 14, 2018 at 12:51

3 Answers 3

3
$\begingroup$

Using SetAttributes is an overkill. (As discussed here.)

Here is a more direct way of getting the desired outcome in the way you want:

list = RandomInteger[10, 10];
function[listArg_] :=
 Module[{list = listArg, a},
  a = Length[list];
  For[i = 1, i < a + 1, i++, 
   If[list[[i]] >= 5, list[[i]] = list[[i]]^2, 
    list[[i]] = list[[i]]^0.5];
   Print["iteration ", i, ", ", list[[]]]]
  ]
function[list]

Now I would say that a more functional way is this one:

function[list_] :=
 FoldList[(
    Echo[{#2, 
       ReplacePart[#1, #2 -> 
         If[#1[[#2]] >= 5, #1[[#2]]^2, #1[[#2]]^0.5]]}, 
      "{iteration,result}="][[2]]
    ) &, list, Range[Length[list]]]

But that might be too complicated for someone with only imperative programming background ...

$\endgroup$
3
  • $\begingroup$ Thank you for your answer. $\endgroup$
    – user57225
    Apr 14, 2018 at 15:16
  • $\begingroup$ Thank you for your answer. I can see that you know a lot about his program. I have read two books about wolfram mathematica, one is "Programming with mathematica , and introduction" and "Hands‑On Start to Wolfram Mathematica: ". I have learned a lot but I would like to get some more knowledge. What would you suggest me to read or do next? $\endgroup$
    – user57225
    Apr 14, 2018 at 15:22
  • 1
    $\begingroup$ @user57225 I am not sure I can offer better books. The books I used 25 years ago are still actual when it comes to functional programming with Mathematica, but, of course, use much less core functions and functionalities. The book "Applied Mathematica: Getting Started, Getting It Done" was very helpful because it is concise. The Roman Maeder books are good sources of learning programming in Mathematica too. $\endgroup$ Apr 14, 2018 at 15:53
5
$\begingroup$

Normal functions are not allowed to modify their argument. But you can give the attribute HoldAll to your function in order to enable what is called call by reference:

list = RandomInteger[10, 10];

ClearAll[function];(*erases all definitions for f*)
SetAttributes[function, HoldAll]
function[list_] := 
 Module[{a = Length[list]}, 
  For[i = 1, i < a + 1, i++, 
   If[list[[i]] >= 5, list[[i]] = list[[i]]^2, 
    list[[i]] = list[[i]]^0.5];
   Print["iteration ", i, ", ", list]]]
function[list]
$\endgroup$
2
  • $\begingroup$ Thank you very much :) $\endgroup$
    – user57225
    Apr 14, 2018 at 10:47
  • $\begingroup$ You're welcome! $\endgroup$ Apr 14, 2018 at 11:38
4
$\begingroup$

While Henriks answer is a correct and precise answer to your actual question I wanted to add some extra information why you usually need to use SetAttributes only very rarely and how that is related with the suggestion to avoid For loops, and in fact many typical approaches you might have learned from writing procedural code in other languages.

Here is how you probably would write a function which calculates the same numbers as your functions:

 function[list_] := Map[If[# >= 5, #^2, #^0.5] &, list]

It admittedly doesn't exactly do what your function does but typically it makes more sense for a function to return something than to print what it does. The function definition shows two things which are very common in Mathematica code: instead of manipulating the list the function returns a new list with the result and it prefers functional over procedural constructs when possible. Because a new list is returned instead of manipulating the input no SetAttributes is needed. Once you get used to those patterns, you will need to "pass by reference" only in very special and rare circumstances.

$\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.