I have written following piece of codes which is a part of very larger program.

x = ConstantArray[0, 7];
i0 = Range[-2, 2]/2;
i1 = RandomReal[{-2, 2}, {400, 7}];
For[u = 1, u <= 7, u++, x[[u]] = Position[Abs[i1[[300, u]] - i0], Min[Abs[i1[[300, u]] - i0]]]];

The question is when I am going to change it in a way to look simpler by defining a function as:

index[u_] := Abs[i1[[300, u]] - i0];

and the For loop like:

For[u = 1, u <= 7, u++, x[[u]] = Position[index[u], Min[index[u]]]];

I face this error:

SetDelayed::write: Tag Abs in Abs[{1.,0.5,0.,-0.5,-1.}+{0.498994,2.91363,1.70631,-0.708323,-1.91564,-0.708323,1.70631}][u_] is Protected.

Note that the number "300" has been chosen arbitrarily and it can be any number between "1" and "400" or the For command itself can be in an outer loop iterating "1-400". Thanks in advance.

  • 1
    $\begingroup$ try with clean Kernel before trying the second case loop. Do you still get the error? Or write ClearAll[x,i0,i1] before trying again. $\endgroup$
    – Nasser
    Jun 10 '19 at 6:49
  • $\begingroup$ Besides, you might get a slightly faster execution time when changing the For loop to Position[index[#], Min[index[#]]] & /@ Range[7] $\endgroup$
    – mgamer
    Jun 10 '19 at 7:26

There's no need to use Position, it's faster to just look for the position of the smallest element directly with Ordering:

i0 = Range[-2, 2]/2;
i1 = RandomReal[{-2, 2}, {400, 7}];
x = Table[First[Ordering[Abs[i1[[300, u]] - i0], 1]], {u, 7}]

Also, Table is generally preferred over pre-allocating a list and populating it with For.

If you insist on the format of x with the nested curly braces, then replace the last line with

x = Table[{Ordering[Abs[i1[[300, u]] - i0], 1]}, {u, 7}]

Rewriting it like this fixes the error:

index[start_Integer, u_Integer] := Abs[i1[[start, u]] - i0];

Then, your for loop becomes this

For[u = 1, u <= 7, u++, x[[u]] = Position[index[300, u], Min[index[300, u]]]];

This yields the same result as your initial code and uses a function.

One suggestion, try to avoid "For" loops. Since you are just iterating over a row, this would do the trick:

With[{row = i1[[300]]}, Position[Abs[# - i0], Min[Abs[# - i0]]] & /@ row]

It also yields the same result, which is this: {{{3}}, {{1}}, {{3}}, {{5}}, {{3}}, {{1}}, {{5}}}


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.