33
$\begingroup$

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.

$\endgroup$
3
  • $\begingroup$ 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} ? $\endgroup$
    – Artes
    Commented Mar 13, 2013 at 20:24
  • 6
    $\begingroup$ @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! $\endgroup$
    – whuber
    Commented Mar 13, 2013 at 20:41
  • $\begingroup$ Related: (15153) $\endgroup$
    – Mr.Wizard
    Commented Mar 13, 2013 at 23:24

5 Answers 5

35
$\begingroup$

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 &
$\endgroup$
1
  • 1
    $\begingroup$ Thank you very much, this is exactly what I was looking for. $\endgroup$
    – John
    Commented Mar 13, 2013 at 20:32
23
$\begingroup$

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}
$\endgroup$
12
$\begingroup$

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} *)
$\endgroup$
2
  • $\begingroup$ 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? $\endgroup$
    – Mr.Wizard
    Commented Mar 16, 2013 at 14:15
  • 4
    $\begingroup$ @Mr.Wizard Done. (But if you were a real wizard, couldn't you just make it magically happen?) $\endgroup$ Commented Mar 16, 2013 at 20:44
9
$\begingroup$

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}
$\endgroup$
3
  • 2
    $\begingroup$ This is the method I would use, expect perhaps as Union @ Cases[Leff, s_Symbol /; Context[s] =!= "System`", -1] $\endgroup$
    – Mr.Wizard
    Commented Mar 13, 2013 at 23:11
  • $\begingroup$ @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 :) $\endgroup$ Commented Mar 14, 2013 at 7:46
  • $\begingroup$ Thank you, the expressions I usually work with are not so complicated but I might need this sometimes. $\endgroup$
    – John
    Commented Mar 14, 2013 at 15:19
3
$\begingroup$
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} *)
$\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.