12
$\begingroup$

I have a For loop (with i as a counter), which calculates different values (y1, y2, y3,...) as a function of the variable x. How can I create a table/matrix which contains i lines, each line containing the variable x_i and the values (y1_i, y2_i, y3_i,...)?

$\endgroup$
2
  • 2
    $\begingroup$ Hi @Solarboy, welcome to MMA.SE. In the future, it would be helpful to have a minimal example of what you've tried. That way the answers can be more specific. $\endgroup$
    – tkott
    Commented Mar 14, 2012 at 10:24
  • $\begingroup$ A relevant doc page here. $\endgroup$ Commented Mar 14, 2012 at 18:30

4 Answers 4

16
$\begingroup$

Typically the best way to accumulate results from an arbitrary process is to use Sow and Reap.

I picked four functions of i as an example. Since there are four, I Partition at the end into subsets of four:

Reap[
  For[i = 1, i < 10, i++, Sow[i]; Sow[i^2]; Sow[i!]; Sow[N@Log@i]];
][[2, 1]] ~Partition~ 4
{{1, 1, 1, 0.},
 {2, 4, 2, 0.693147},
 {3, 9, 6, 1.09861},
 {4, 16, 24, 1.38629},
 {5, 25, 120, 1.60944},
 {6, 36, 720, 1.79176},
 {7, 49, 5040, 1.94591},
 {8, 64, 40320, 2.07944},
 {9, 81, 362880, 2.19722}}

If you can formulate your code to do a single Sow for each row it will be cleaner:

Reap[
  For[i = 1, i < 10, i++, Sow[{i, i^2, i!, N@Log@i}]];
][[2, 1]]

Brett Champion recommended that I show the two argument from of Sow, which groups results according to explicit tags.

Sow[e, tag]
specifies that e should be collected by the nearest enclosing Reap whose pattern matches tag.

Sow[e, {tag1, tag2, ...}]
specifies that e should be collected once for each pattern that matches a tagi.

(See this answer for a powerful use of the multiple tag form.)

Here is an example using this in place of Partition in the case of separate Sow expressions per loop.

Reap[
 For[i = 1, i < 10, i++, Sow[i, i]; Sow[i^2, i]; Sow[i!, i]; Sow[N@Log@i, i]];
][[2]]

Also, with a few exceptions it is better to avoid For in Mathematica and use constructs such as Table, Do, Array, Map, NestWhile, FixedPointList and others. I chose to answer your direct question rather than to answer with what I think you should use instead. If you are interested in alternative ways to write your program you should post a new question to that effect with an example For loop you wish to optimize.

$\endgroup$
8
  • $\begingroup$ Glad someone brought up Sow and Reap... You should mention the two-argument form, though, since otherwise you can run into problems down the road. (Like needing to resort to Partition.) $\endgroup$ Commented Mar 14, 2012 at 21:04
  • $\begingroup$ Why didn't you use Do instead of For? For these cases (doing simple tests) it shows as a faster solution. $\endgroup$
    – FJRA
    Commented Mar 15, 2012 at 1:12
  • $\begingroup$ @FJRA you already showed a "better" way using Table. István references Array. I wanted to answer the OP's question directly and show best how results may be accumulated from within For or any other construct. $\endgroup$
    – Mr.Wizard
    Commented Mar 15, 2012 at 7:54
  • $\begingroup$ @Brett I'll add an example. $\endgroup$
    – Mr.Wizard
    Commented Mar 15, 2012 at 7:55
  • $\begingroup$ @Mr.Wizard your last comment points out what István started saying: there are a million ways to do this! $\endgroup$
    – FJRA
    Commented Mar 15, 2012 at 13:03
12
$\begingroup$

Try using Table, assuming x is an array of values you could try:

matrix = Table[{xi, y1[xi], y2[xi], ..}, {xi, x}]

Table will "do the For loop" while building matrix, in this case xi will take each value of x.

And if y functions is also an array, you can use a nested Table:

matrix = Table[{xi, Sequence@@Table[y[xi,j], {j, n}]}, {xi, x}]

Here j is the index for the second table, which will run from 1 to n.

$\endgroup$
6
$\begingroup$

Now this is the kind of question that can be answered in a million ways:

yRange = 4;
iRange = 6;

(* using Table & Map *)
Table[{Subscript[x, i], 
   Sequence @@ Map[Subscript[y, #, i] &, Range[yRange]]}, {i, 
   6}] // Column

(* using Map & Table *)
Map[Prepend[Table[Subscript[y, j, #], {j, yRange}], 
    Subscript[x, #]] &, Range[iRange]] // Column

(* using MapThread & Array *)
MapThread[
  Prepend,
  {Transpose@Array[Subscript[y, ##] &, {yRange, iRange}], 
   Array[Subscript[x, ##] &, {iRange}]}] // Column

All returning:

Mathematica graphics

$\endgroup$
4
$\begingroup$

Without having your for loop in hand, you could also do something like the following:

myMatrix = {}; (* Initialize the list *)

For[i=0, i<Something, i++, 
  (* ... you do something here *)
  AppendTo[myMatrix,{xi, y1[xi], y2[xi], ..}]

  (* ... do other things .. *)
]

Or you could combine the a call to Table as @FJRA suggests for the "inner loop" j with the For loop like above.

$\endgroup$
1
  • $\begingroup$ @Sjoerd Thanks for the edit, I guess I was writing too many comments :) $\endgroup$
    – tkott
    Commented Mar 14, 2012 at 18:29

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.