# For loop works at top-level but not in a function

Why does this work:

For[i = 1, i <= Dimensions[list][[1]], i++, list = Insert[list, i, {i, 3}]]


But this doesn't:

insertColumns[list_] :=
For[i = 1, i <= Dimensions[list][[1]], i++,
list = Insert[list, i, {i, 3}]]


I get a message saying that something in the part assignment is not a symbol. But this:

insertColumns[list_] :=
For[i = 1, i <= Dimensions[list][[1]], i++,
Return[FullForm[list[[i]]]]]


Returns this result:

List[1,"Red","Name","Random"]


I am very new to Mathematica, so please be kind :)

• Try insertColumns[list_ List] to indicate a list is input. Apr 16, 2016 at 2:11
• That seems to get rid of the error messages, but just returns insertColumns[{the list of things I gave it}] Apr 16, 2016 at 3:38
• What is the input you're using? To reproduce the error you should let us know what list you actually used.
– Jens
Apr 16, 2016 at 3:39
• {{1, "Red", "Name", "Random"}, {1, "Red", "Tim", "asdfg"}} So when I pass this to the function, it just returns: insertColumns[{{1, "Red", "Name", "Random"}, {1, "Red", "Tim", "asdfg"}}] Apr 16, 2016 at 3:46
• With a slight modification it works - see my answer.
– Jens
Apr 16, 2016 at 3:50

Assuming you use a list input that is appropriate for use with Insert as it appears in the function, you would only have to localize list to avoid further errors:

insertColumns[list_] :=
Module[{l = list},
For[i = 1, i <= Dimensions[list][[1]], i++,
l = Insert[l, i, {i, 3}]]; l]

insertColumns[{{a1, b1, c1}, {a2, b2, c2}, {a3, b3, c3}}]

(* ==> {{a1, b1, 1, c1}, {a2, b2, 2, c2}, {a3, b3, 3, c3}} *)

insertColumns[{{1, "Red", "Name", "Random"}, {1, "Red",
"Tim", "asdfg"}}]

(*
==> {{1, "Red", 1, "Name", "Random"}, {1, "Red", 2, "Tim",
"asdfg"}}
*)


However, this entire approach is of course very un-Mathematica-like.

Explanation

The reason why you have to localize the variable list is that Mathematica uses what can be called "pass-by-value" in which the argument list is resolved into the actual list of entries. The dummy variable name list represents a function slot and is not actually a Symbol to which you should try to assign things. There is no need to know about this when you just extract values from list (as with the dimension in your code), but you get into trouble when actually trying to assign new values to the arguments named by the dummy variable list.

The assignment by Set (=) in the For loop sees a list structure on both sides of the equation, and attempts to Thread over it to make the assignment element-wise. But since the right-hand side is a modified version of list in which elements have been added, the dimensions of the lists in Set don't match. This causes an error.

The localized variable l is treated as a Symbol and not a "dummy variable", so Set doesn't try to match dimensions in that case. This is why the above code avoids the error.

The other issue is one of aesthetics and efficiency. In the For loop, the entire list is copied in every step. Also, simple iterations are often better done using special constructs that operate on Lists without explicitly introducing a counter index, as required in For. There is a lot of relevant information about this in the post Elegant operations on matrix rows and columns. The MapIndexed approach in @m_goldberg's answer is mentioned there, too.

• could you please explain what you mean by un-Mathematica-like? I'd rather be working with the language than fighting it. Apr 16, 2016 at 18:18
• Also, could you clarify why my original code doesn't work inside the function, but this does? Apr 16, 2016 at 18:44
• OK, I've added an explanation.
– Jens
Apr 16, 2016 at 20:33

As Jens says your approach is not very Mathematica-like, i.e., it doesn't make good use of Mathematica's strengths. Here is an implementation that I hope Jens would agree makes better use of those strengths. Although it is more concise than your method, it has more generality; you can pick the column where the index of the list element is inserted.

insertIndex[data_List, col_Integer] /; 0 < col <= Length[data[[1]]] + 1 :=
MapIndexed[Insert[#1, #2[[1]], col] &, data]


To digest this answer, you should look up MapIndexed, Part and Function in the Documentation Center. The article under Part will explain the [[ ]] notation and article under Function will explain the #1, #2, and & stuff.

The rather elaborate formal argument pattern is designed restrict arguments to valid ones -- not perfectly, but usefully.

### Testing

First I generate a list of 6 3-element lists.

data[n_] := With[{names = Alphabet[]}, Table[RandomSample[names, 3], n]]
SeedRandom[42]; test = data[6]


{{"n", "u", "e"}, {"c", "b", "g"}, {"a", "t", "e"}, {"d", "i", "m"}, {"a", "h", "i"}, {"w", "z", "g"}}

Then I have insertIndex insert the index of each sublist at positions 1 to 4

Table[insertIndex[test, col], {col, Length[test[[1]]] + 1}]

{{{1, "n", "u", "e"}, {2, "c", "b", "g"}, {3, "a", "t", "e"},
{4, "d", "i", "m"}, {5, "a", "h", "i"}, {6, "w", "z", "g"}},
{{"n", 1, "u", "e"}, {"c", 2, "b", "g"}, {"a", 3, "t", "e"},
{"d", 4, "i", "m"}, {"a", 5, "h", "i"}, {"w", 6, "z", "g"}},
{{"n", "u", 1, "e"}, {"c", "b", 2, "g"}, {"a", "t", 3, "e"},
{"d", "i", 4, "m"}, {"a", "h", 5, "i"}, {"w", "z", 6, "g"}},
{{"n", "u", "e", 1}, {"c", "b", "g", 2}, {"a", "t", "e", 3},
{"d", "i", "m", 4}, {"a", "h", "i", 5}, {"w", "z", "g", 6}}}