7
$\begingroup$

Having said that I'm no expert, I have some problems in generating a list of functions inside a loop. The functions in the list should depend on the elements of a parameters list, that are read in sequence. The stripped down examples here below should show what I mean. First I tried this (rather naively)

parameters = {a, 3, 6, E, 2}; p = 1;
While[p <= 5, funclist[[p]][x_] := parameters[[p]] x^p; p++]

Naturally it doesn't work. After some other trials I arrived at this possible solution

parameters = {a, 3, 6, E, 2}; p = 1;
While[p <= 5, With[{p = p}, funclist[p, x_] := parameters[[p]] x^p]; p++]

But in this case the output is not actually a list but rather a sort of indexed function that cannot be manipulated as a list could be.

What I'd like to get is a list of functions that, for example can be used in the following ways:

in: funclist
out: {a x, 3 x^2...}

and also

in: funclist[[2]][4]
out: 48

or also

Plot[funclist[[2]],{x,-1,5}]

Is it possible?

$\endgroup$
0

6 Answers 6

3
$\begingroup$

The question contains conflicting requirements. On the one hand, it wants funclist to behave like a list of functions so that we can write funclist[[2]][4] and get a value. On the other hand, it wants funclist to act like a list of expressions in x so that we can write Plot[funclist[[2]], {x, -1, 5}]. The two requirements are incompatible: we will need to choose between them.

Functions

If we wish funclist to behave like a list of functions, we can do this:

parameters = {a, 3, 6, E, 2};

funclist = Function /@ (parameters # ^ Range@Length@parameters)

(* {a #1 &, 3 #1^2 &, 6 #1^3 &, E #1^4 &, 2 #1^5 &} *)

Then:

funclist[[2]][4]

(* 48 *)

But we must pass an explicit argument to one these functions in order to plot it:

Plot[funclist[[2]][x], {x, -1, 5}]

plot screenshot

Expressions in x

Alternatively, we can have funclist contain a list of expressions in x:

funclist = parameters x ^ Range@Length@parameters

(* {a x, 3 x^2, 6 x^3, E x^4, 2 x^5} *)

But now we cannot invoke them like functions. To evaluate them, we need to replace x:

funclist[[2]] /. x -> 4

(* 48 *)

Plotting, on the other hand, does not require anything special:

Plot[funclist[[2]], {x, -1, 5}]

plot screenshot

Academic Exercise: Both?!

Earlier it was stated that we cannot have funclist behave both as a list of functions and as a list of expressions. This is not entirely true. If we are willing to damn the torpedoes and steam in anyway, it is possible to make it happen. This is not a serious proposal. It is simply a demonstration that the Wolfram language is very malleable, if we are determined enough.

We start by defining xfuns, which masquerades as an innocent list. In fact, it serves as a factory to produce these hybrid function/expression objects:

Format[xfuns[e___]] := {e}
xfuns[e___][[i_]] ^:= With[{a = {e}[[i]]}, xfun[a]]

Next we define xfun, a wrapper that implements the hybrid behaviour:

xfun[e_] /; MatchQ[Stack[], {___, Null, xfun, MatchQ}] := Function @@ {{x}, e}
xfun[x_] := x

This nasty piece of business looks up the call stack to see whether or not it is being applied to an argument. If it is, it returns a function. Otherwise it returns an expression.

Here it all is in action:

funclist = xfuns @@ (parameters x ^ Range@Length@parameters)

(* {a x, 3 x^2, 6 x^3, E x^4, 2 x^5} *)

funclist looks like a list of expressions in x. The individual elements resolve to expressions as well:

funclist[[2]]

(* 3 x^2 *)

Plot agrees:

Plot[funclist[[2]], {x, -1, 5}]

plot screenshot

But... they can be used as functions too!

funclist[[2]][4]

(* 48 *)

Pure evil. I emphasize again: this is not a recommended practice. This is just for fun. Programming in this style means that expressions evaluate in unexpected ways, creating a fertile breeding ground in which bugs can thrive.

$\endgroup$
8
$\begingroup$

Because of what I consider serious overlap with later answers (either with the beginning of this answer, or the later part) I feel compelled to note that this answer covers two different methods.

Sure, it's possible. But not quite in the way you imagined.

Clear[a, x, p];
parameters = {a, 3, 6, E, 2};
funclist = MapIndexed[# x^(First@#2) &, parameters]

{a x, 3 x^2, 6 x^3, E x^4, 2 x^5}

This looks right, just like your list, but they aren't functions so you can't evaluate them the way you hoped to. Instead we have to do something like

With[{x = 4}, Evaluate@funclist[[2]]]

48

where Evaluate is needed because that rewrites the expression so that x appears explicitly. With will only replace symbols that appear explicitly in the expression in its body. This is also needed to plot any of the expressions because, again, x has appear explicitly:

Plot[Evaluate@funclist[[2]], {x, -1, 5}] 

Plot example

You can write a list of functions that will execute the way you want, but the list won't look the way it does in your example. You could do it like this:

funclist = MapIndexed[Function[{x}, # x^(First@#2)] &, parameters]
{Function[{x}, a x^First[{1}]], Function[{x}, 3 x^First[{2}]],  
 Function[{x}, 6 x^First[{3}]], Function[{x}, E x^First[{4}]],  
 Function[{x}, 2 x^First[{5}]]}
funclist[[2]][4]

48

And for the plot:

Plot[funclist[[2]][x], {x, -1, 5}]

EDIT: As seismatica pointed out to me, using Evaluate inside funclist makes the output better looking:

funclist = MapIndexed[Function[{x}, Evaluate[# x^(First@#2)]] &, parameters]

{Function[{x}, a x], Function[{x}, 3 x^2], Function[{x}, 6 x^3], Function[{x}, E x^4], Function[{x}, 2 x^5]}

$\endgroup$
2
  • $\begingroup$ I was probably the first one to upvote your answer. Before you find further "overlaps": What's with Plot[Evaluate@funclist[[1]], {x, -1, 5}] ??? $\endgroup$
    – eldo
    Sep 6, 2014 at 21:36
  • $\begingroup$ @eldo Thanks for the vote. That's what I need to make it work, isn't it? $\endgroup$
    – C. E.
    Sep 6, 2014 at 21:39
5
$\begingroup$

There is also a solution without the need for Evaluate.

parameters = {a, 3, 6, E, 2};
funclist = Table[p #^e & /. {p -> parameters[[n]], e -> n}, {n, 1, 5}];

The # and & are abbreviations for building pure functions. # stands for the varaible and & has to be put at the end of the expression to build a function.

Then you can use funclist like this:

funclist[[2]][4]
(* 48 *)

or

Plot[funclist[[2]][x], {x, 0, 1}]

enter image description here

$\endgroup$
5
$\begingroup$

Instead of creating a list of functions, I would simply use

func[p_][x_] := parameters[[p]] x^p

To avoid accidental modification of parameters, I might use

func`parametes = {...};
func[p_][x_] := func`parameters[[p]] x^p

Then you can use func[1] as a function, or if you really need them stored in a list, func /@ Range[5] gives you that.

Definitions of the form f[...][...]...[...] := ... (i.e. having more than one [...]) are called sub-value definitions.

$\endgroup$
1
  • $\begingroup$ func[5][x] functions with me. But func /@ Range[5]` doesn't. Please clarify. $\endgroup$
    – eldo
    Sep 6, 2014 at 21:49
3
$\begingroup$
para = {a, 3, 6, E, 2};

fun = Map[para[[#]] x^# &, Range @ 5]

{a x, 3 x^2, 6 x^3, E x^4, 2 x^5}

Plot[
 Evaluate @ Map[fun[[#]] /. a -> 700 &, Range @ 5],
 {x, 0, 10},
 PlotStyle -> {Black, Red, Green, Blue, Orange},
 PlotTheme -> "Detailed",
 ImageSize -> 600]

enter image description here

$\endgroup$
1
$\begingroup$

I would suggest (to make easier) to do it like this:

 parameters = {a, 3, 6, E, 2};
    funclist[x_]=# x^Range[Length[#]] &[parameters]
    (*{a x, 3 x^2, 6 x^3, E x^4, 2 x^5}*)
    funclist[4][[2]]
    (*48*)
    Plot[funclist[x][[2]],{x,-1,5}]
$\endgroup$

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.