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
,...)?
-
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$– tkottCommented Mar 14, 2012 at 10:24
-
$\begingroup$ A relevant doc page here. $\endgroup$– Sjoerd C. de VriesCommented Mar 14, 2012 at 18:30
4 Answers
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.
-
$\begingroup$ Glad someone brought up
Sow
andReap
... You should mention the two-argument form, though, since otherwise you can run into problems down the road. (Like needing to resort toPartition
.) $\endgroup$ Commented Mar 14, 2012 at 21:04 -
$\begingroup$ Why didn't you use
Do
instead ofFor
? For these cases (doing simple tests) it shows as a faster solution. $\endgroup$– FJRACommented Mar 15, 2012 at 1:12 -
$\begingroup$ @FJRA you already showed a "better" way using
Table
. István referencesArray
. I wanted to answer the OP's question directly and show best how results may be accumulated from withinFor
or any other construct. $\endgroup$ Commented Mar 15, 2012 at 7:54 -
-
$\begingroup$ @Mr.Wizard your last comment points out what István started saying: there are a million ways to do this! $\endgroup$– FJRACommented Mar 15, 2012 at 13:03
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
.
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:
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.
-
$\begingroup$ @Sjoerd Thanks for the edit, I guess I was writing too many comments :) $\endgroup$– tkottCommented Mar 14, 2012 at 18:29