7

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?

Luca M
  • 997
  • 1
  • 6
  • 18

6 Answers6

8

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

C. E.
  • 70,533
  • 6
  • 140
  • 264
  • 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}] ??? – eldo Sep 06 '14 at 21:36
  • @eldo Thanks for the vote. That's what I need to make it work, isn't it? – C. E. Sep 06 '14 at 21:39
5

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

DaveStrider
  • 701
  • 5
  • 8
5

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.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
3
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

eldo
  • 67,911
  • 5
  • 60
  • 168
3

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.

WReach
  • 68,832
  • 4
  • 164
  • 269
1

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}]
Basheer Algohi
  • 19,917
  • 1
  • 31
  • 78