6

I would like to get a List (ideally a set -- discarding repetition -- but assuming there's no direct way to do this I'll just use Union) of the leaves from a given expression.

For example, the expression

ArcTan[(-1 + 2*x)/Sqrt[3]]/Sqrt[3]

has a LeafCount of 18:

  • -1 (3)
  • 2 (3)
  • 3 (2)
  • x
  • ArcTan
  • Plus
  • Power (2)
  • Rational (2)
  • Times (3)

so I would like something like

{-1, 2, 3, x, ArcTan, Plus, Power, Rational, Times}

Actually, I really just want the functions so

{ArcTan, Plus, Power, Rational, Times}

would be ideal -- but presumably there's some not-too-difficult way to filter these when I have them.

I've had some luck with

H[s_] := If[LeafCount[s] == 1, s, Head[s]]
H /@ Level[expr, 1, Heads -> True]
H /@ Level[expr, 2, Heads -> True]
(* ... *)

but I feel like there must be a better way.

Charles
  • 11,269
  • 13
  • 67
  • 105

4 Answers4

8

You could use Cases for this:

In[176]:= 
Cases[ArcTan[(-1 + 2*x)/Sqrt[3]]/Sqrt[3], h_[___] :> h, 
  {0,Infinity}] // DeleteDuplicates

Out[176]= {Rational, Power, Times, Plus, ArcTan}
Brett Champion
  • 8,497
  • 1
  • 27
  • 44
7

Your own solution does not seem bad:

expr = ArcTan[(-1 + 2*x)/Sqrt[3]]/Sqrt[3];

H[s_] := If[LeafCount[s] == 1, s, Head[s]]

H /@ Level[exp, -1, Heads -> True] // Union
{-1, 2, 3, ArcTan, Plus, Power, Rational, Times, x}

Brett Champion's method is more streamlined, but I would change it a little:

Union@Cases[expr, h_[___] :> h, {0, -1}]

This way you pick up a top level head, such as ArcTan in:

expr = ArcTan[(-1 + 2*x)/Sqrt[3]];
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • 1
    +1, the level spec, `{0,-1}`, is quite clever: level 0 -> the entire expression, level -1 -> everything without subparts (i.e. the leaves). So, it essentially tells `Cases` to work from top to bottom of the expression tree. Nice! – rcollyer Aug 19 '11 at 02:27
6

For the original question, one can get all leaves via Level with level spec of {-1} and allowing for heads.

In[87]:= Level[ArcTan[(-1 + 2*x)/Sqrt[3]]/Sqrt[3], {-1}, Heads -> True]

Out[87]= {Times, Power, 3, -(1/2), ArcTan, Times, Power, 3, -(1/
    2), Plus, -1, Times, 2, x}

Daniel Lichtblau

Daniel Lichtblau
  • 6,854
  • 1
  • 23
  • 30
4

Here's what I came up with...

In[92]:= f[e_] := DeleteDuplicates[Prepend[Head[#] & /@ Level[e, Depth[e]], Head[e]]]

In[93]:= f[ArcTan[(-1 + 2*x)/Sqrt[3]]/Sqrt[3]]

Out[93]=  {Times, Integer, Rational, Power, Symbol, Plus, ArcTan}

You can then easily remove Integer and Symbol.


Edit:

Now let's wrap the expression in a list to make sure we're getting the uppermost head. (The original expression had Times as its head but it was also twice inside.

In[139]:= a = {ArcTan[(-1 + 2*x)/Sqrt[3]]/Sqrt[3]}
In[140]:= TreeForm[a, AspectRatio -> .7]

TreeForm

In[142]:= f[a]
Out[142]= {List, Integer, Rational, Power, Symbol, Times, Plus, ArcTan}
DavidC
  • 3,056
  • 1
  • 20
  • 30