Getting all the leaves from an expression
Asked Answered
T

4

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.

Turves answered 18/8, 2011 at 20:35 Comment(0)
S
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]];
Spam answered 18/8, 2011 at 21:3 Comment(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!Meyerhof
H
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}
Hemistich answered 18/8, 2011 at 20:43 Comment(0)
S
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]];
Spam answered 18/8, 2011 at 21:3 Comment(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!Meyerhof
D
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

Daves answered 18/8, 2011 at 21:4 Comment(3)
Where is Rational? The OP requested this.Spam
@Mr. Wizard I had missed that. In general types that are regarded as "atomic" by Mathematica will not have heads obtained via Level. Depending on what is really wanted that might or might not be a drawback.Daves
+1 for the {-1}. I suspect its more efficient than using Depth.Hurricane
H
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}
Hurricane answered 18/8, 2011 at 21:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.