2
$\begingroup$

I'm trying to use Table[] more to be more in the spirit of Mathematica. So for example, I might replace this piece of code:

MySimpleFn[a_] := (
  Return[a^5];)

myList = {};
Do[fnOutput = MySimpleFn[i]; 
  AppendTo[myList, {i, fnOutput}];, {i, 5}];

With the more efficient

MySimpleFn[a_] := (
  Return[a^5];)

Table[{i, MySimpleFn[i]}, {i, 5}]

But now let's say instead of MySimpleFn[], it's a function that takes a significant amount of time to calculate, MyHugeMessyLongFn[], and instead of one return value, it returns a pair, {a,b}.

Now, I know how I'd avoid calling the function twice with a loop, just:

myList = {};
Do[
fnOutput = MyHugeMessyLongFn[i];
fnOutput1 = fnOutput[[1]]; 
fnOutput2 = fnOutput[[2]]; 
  AppendTo[myList, {i, fnOutput1,fnOutput2}];, {i, 5}];

But how can I do this with Table[]? If I did

 Table[{i, MyHugeMessyLongFn[i][[1]], MyHugeMessyLongFn[i][[2]]}, {i, 5}]

I assume it would call it twice, right? Is there a way to use table for more extended operations, essentially?

$\endgroup$
2
  • $\begingroup$ Although the question is about basic issues, I think it shows a great effort in trying to overcome the problem. Good work! BTW, I believe you can try reading this for some general Mma programming considerations: mathematica.stackexchange.com/q/18393/193 $\endgroup$ Oct 29, 2014 at 0:09
  • 1
    $\begingroup$ related $\endgroup$
    – Kuba
    Oct 29, 2014 at 7:30

5 Answers 5

2
$\begingroup$

You just need to Flatten each row in the Table result to get the form you are looking for. Use the same kind of expression that you are using for MySimpleFn but flatten the rows.

Table[{i, MyHugeMessyLongFn[i]} // Flatten, {i, 5}]
$\endgroup$
2
$\begingroup$

Aside from the myriad of ways of better vectorising your task, what you are probably looking for is With. For example,

With[{s = MyHugeMessyLongFn[i]}, {s, 2s, First @ s}]

This can be used anywhere, including within a Table. It is just a scoped assignment to the variable s. You could have an unscoped version too:

(s = MyHugeMessyLongFn[i]; {s, 2s, First @ s})

But this is generally considered bad programming (it overwrites any existing value of s, and retains the assignment after you are done).

$\endgroup$
2
$\begingroup$

Another mm-ish way to approach this is to memoize the function (note the ":=: and "="):

MyHugeMessyLongFn[a_]:=MyHugeMessyLongFn[a]=(someTimeConsumingStuff);

and then do as you suggested:

Table[{i, MyHugeMessyLongFn[i][[1]], MyHugeMessyLongFn[i][[2]]}, {i, 5}]

Your function will be called twice, but the second time it will just remember its value from the first time.

BTW, you might as well get MyHugeMessyLongFn to return a triplet that starts with {a,...} and then do

Table[MyHugeMessyLongFn[i], {i, 5}]

which can be written as

MyHugeMessyLongFn /@ Range@5
$\endgroup$
2
$\begingroup$

This question really amounts to: how can one manipulate lists in Mathematica? The most popular tag is in fact so there are a myriad of examples available to you.

Other than memoization as proposed by A.G. all methods rely on calling the function only once, then doing something with the expression that is returned. You can manipulate each element at the first level of a returned expression (i.e. elements of a list) by Apply-ing a Function to it:

bar[#2, z, #1, #1 + #2] & @@ {one, two}
bar[two, z, one, one + two]
  • Here {one, two} would be the output of your MyHugeMessyLongFn
  • bar[#2, z, #1, #1 + #2] is the body of the anonymous Function defined with &; it is the output wish to create
  • @@ is short for Apply.
  • Note that every appearance of #1 has been replaced with the first element of {one, two} and every appearance of #2 with the second element. These are known as Slot expressions.

Another method that is more general, allowing you to simultaneously address elements at different levels of a returned expression is to use destructuring. This has a potential clarity advantage as well because parts are named rather than numbered. Example:

{one, two} /. {a_, b_} :> bar[b, z, a, a + b]
bar[two, z, one, one + two]
  • Here {one, two} again represents the output of your long function
  • /. is the short form of ReplaceAll.
  • {a_, b_} is a pattern (using Blank) that matches the output of your long function; it is the left hand side of a replacement rule
  • :> is the short form of RuleDelayed
  • bar[b, z, a, a + b] is the body of the replacement rule
  • Note that every appearance of a in the body is replaced with one and every b with two.

The methods above are the ones that I prefer but if you find them confusing you can also use With to name your output and then use Part which you appear to be familiar with:

With[{r = {one, two}},
  bar[r[[2]], z, r[[1]], r[[1]] + r[[2]]]
]
bar[two, z, one, one + two]

Personally I find this harder to read due to all the brackets but you may disagree.

$\endgroup$
1
$\begingroup$

This is more Mathematica-ish:

MyHugeMessyLongFn[x_] := {2 x, 3 x}
myList = {#, MyHugeMessyLongFn@#} & /@ Range@5

(* {{1, {2, 3}}, {2, {4, 6}}, {3, {6, 9}}, {4, {8, 12}}, {5, {10, 15}}}
*)
$\endgroup$
1
  • $\begingroup$ Or SetAttributes[MyHugeMessyLongFn, Listable]; Transpose[{Range[5], MyHugeMessyLongFn@Range[5]}] $\endgroup$ Oct 28, 2014 at 23:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.