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

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.


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}}}