# Get a Symbol vector of all variable names in an Expr?

Is there a simple and type stable way to do this?

``````julia> f(:(x^2+sum(x,y-3,z)))

4-element Array{Symbol,1}:
:x
:x
:y
:z
``````
1 Like

It’s pretty easy to walk expression trees, typing `:(x^2+1) |> dump` etc. will let you see how they are structured. Here’s a rough solution, but there are expressions which will trip this up:

``````julia> walk!(list) = ex -> begin
ex isa Symbol && push!(list, ex)
ex isa Expr && ex.head == :call && map(walk!(list), ex.args[2:end])
list
end
walk! (generic function with 1 method)

julia> :(x^2+sum(x,y-3,z)) |> walk!([])
4-element Array{Any,1}:
:x
:x
:y
:z
``````
1 Like

MacroTools.jl Expression Walking can iterate expressions.

1. How to get just `x, y, z` (from both `ex1` and `ex2`) and not `+,-,^,sum`?
2. How to return the list directly from postwalk instead of pushing to external list?
``````import MacroTools: postwalk

function get_ex_symbols1(ex)
list = []
postwalk(x -> x isa Symbol ? (push!(list, x); x) : x, ex)
return Set{Symbol}(list)
end

function get_ex_symbols2(ex)
list = []
walk!(list) = ex -> begin
ex isa Symbol && push!(list, ex)
ex isa Expr && ex.head == :call && map(walk!(list), ex.args[2:end])
list
end
Set{Symbol}(walk!([])(ex))
end

ex1 = :(x^2+sum(x,y-3,z))
ex2 = :(function f(x,y); x=x+1; y=y^2; z=sum(x,y) end);
``````
``````julia> get_ex_symbols1(ex1)
Set{Symbol} with 7 elements:
:+
:^
:y
:-
:z
:sum
:x

julia> get_ex_symbols1(ex2)
Set{Symbol} with 7 elements:
:+
:z
:f
:^
:y
:sum
:x

julia> get_ex_symbols2(ex1)
Set{Symbol} with 3 elements:
:y
:z
:x

julia> get_ex_symbols2(ex2)
Set{Symbol}()
``````
1 Like