Extracting variables from an expression

25

6

I'm looking for a way to extract a list of variables from an expression, for example with an input like:

Leff= (mc dm^2 + mc/12*(h^2 + 3 R^2) + ma da^2 + ma/12 La^2)/(mc dm + ma da)

I want this output:

{mc, dm, ma, da, La, h, R}.

The built-in Mathematica function Variables can do this, but it doesn't work with more complex expressions containing trascendental functions. Any help would be very appreciated.

John

Posted 2013-03-13T20:16:35.770

Reputation: 600

Wouldn't it be more natural to use { c, d, a, b, L, h, R} instead of unreasonable and awful {mc, dm, ma, da, La, h, R} ? – Artes – 2013-03-13T20:24:14.190

5@Artes Mnemonics can often be helpful, as well as using variables whose names are as close as possible to a formula as printed in a textbook or paper. Let's blame the paper authors and not the coders for bad variable names! – whuber – 2013-03-13T20:41:03.007

Related: (15153)

– Mr.Wizard – 2013-03-13T23:24:00.510

Answers

28

Assuming you don't have any built-in symbols in that list, you could simply do:

DeleteDuplicates@Cases[Leff, _Symbol, Infinity]
(* {da, ma, dm, mc, La, h, R} *)

If you do have symbols from built-in contexts or packages, you can simply pick out only those that are in the Global` context with:

With[{globalQ = Context@# === "Global`" &},
    DeleteDuplicates@Cases[Leff, _Symbol?globalQ, Infinity]
]

If you have a different default working context (e.g. local to notebook/cell or in a package), change the pattern test to the following, instead of globalQ:

currentContextQ = Context@# === $Context &

rm -rf

Posted 2013-03-13T20:16:35.770

Reputation: 85 395

1Thank you very much, this is exactly what I was looking for. – John – 2013-03-13T20:32:17.007

16

Using an undocumented function:

Reduce`FreeVariables[(mc dm^2 + mc/12*(h^2 + 3 R^2) + ma da^2 + ma/12 La^2)/
                     (mc dm + ma da)]
   {da, dm, h, La, ma, mc, R}

J. M.'s ennui

Posted 2013-03-13T20:16:35.770

Reputation: 115 520

10

The below code for getAllVariables was lifted without attribution from some StackOverflow post.

headlist = {Or, And, Equal, Unequal, Less, LessEqual, Greater, 
   GreaterEqual, Inequality};

getAllVariables[f_?NumericQ] := Sequence[]
getAllVariables[{}] := Sequence[]
getAllVariables[t_] /; MemberQ[headlist, t] := Sequence[]

getAllVariables[ll_List] := 
 Flatten[Union[Map[getAllVariables[#] &, ll]]]

getAllVariables[Derivative[n_Integer][f_][arg__]] := 
 getAllVariables[{arg}]

getAllVariables[f_Symbol[arg__]] := 
 Module[{fvars}, 
  If[MemberQ[Attributes[f], NumericFunction] || MemberQ[headlist, f], 
   fvars = getAllVariables[{arg}],(*else*)fvars = f[arg]];
  fvars]

getAllVariables[other_] := other

Example:

Leff = (mc dm^2 + mc/12*(h^2 + 3 R^2) + ma da^2 + ma/12 La^2)/(mc dm +
     ma da)
getAllVariables[Leff]

(* Out[254]= {da, ma, dm, mc, ma, da, ma, La, mc, dm, mc, h, R} *)

Daniel Lichtblau

Posted 2013-03-13T20:16:35.770

Reputation: 52 368

Daniel, since questions are generally not being migrated any longer and since these valuable posts ultimately fall outside our control, why don't you repost your method as a full answer? – Mr.Wizard – 2013-03-16T14:15:03.423

3@Mr.Wizard Done. (But if you were a real wizard, couldn't you just make it magically happen?) – Daniel Lichtblau – 2013-03-16T20:44:49.553

7

If you have even more complicated expressions, you might want to use Heads -> True.

expr = {f, Subscript[g, i], h[i[j[a, b]]], s'[t] == u[t] + v[t]};

Union @ Cases[expr, Except[__Symbol?(Context @ # === "System`" &), _Symbol], {1, ∞},
              Heads -> True]
{a, b, f, g, h, i, j, s, t, u, v}

Without checking heads:

Union @ Cases[expr, Except[__Symbol?(Context @ # === "System`" &), _Symbol], {1, ∞}]
{a, b, f, g, i, t}

István Zachar

Posted 2013-03-13T20:16:35.770

Reputation: 44 135

2This is the method I would use, expect perhaps as Union @ Cases[Leff, s_Symbol /; Context[s] =!= "System`", -1] – Mr.Wizard – 2013-03-13T23:11:56.950

@Mr.Wizard I've tried to provide code that is sufficiently different from rm-rf-s version not to give room for any comments on plagiarism :) – István Zachar – 2013-03-14T07:46:40.793

Thank you, the expressions I usually work with are not so complicated but I might need this sometimes. – John – 2013-03-14T15:19:49.710

2

expr = (mc dm^2 + mc/12*(h^2 + 3 R^2) + ma da^2 + ma/12 La^2)/(mc dm + ma da); 
Level[expr, {-1}] /. x_?NumericQ :> (## &[]) // DeleteDuplicates
(* {da,ma,dm,mc,La,h,R} *)

kglr

Posted 2013-03-13T20:16:35.770

Reputation: 302 076