Function Repository Resource:

SubexpressionPositions

Source Notebook

Find subexpressions together with their positions

Contributed by: Nikolay Murzin

ResourceFunction["SubexpressionPositions"][expr,opts]

returns an association with position and subexpression of expr that match certain criteria provided in opts.

ResourceFunction["SubexpressionPositions"][expr,levelspec, opts]

finds only subexpressions that appear on the levels specified by levelspec.

ResourceFunction["SubexpressionPositions"][expr,levelspec, n, opts]

return only first n results.

ResourceFunction["SubexpressionPositions"][expr,positions, opts]

select from a given list of positions.

Details and Options

ResourceFunction["SubexpressionPositions"] takes the following options:
"OuterMatch"__outer expressions matching criteria
"InnerMatch"__inner expressions matching criteria
"OuterMode""Any""Any" or All
"InnerMode""Any""Any" or All
"Complement"Falsetake a complement of an overall criteria
HeadsTruewhether to include expression heads
"OuterMatch" and "InnerMatch" are both assumed to be of the form subExprpos (read as "at"), a pair of patterns that would be matched against a subexpression and a relative position under consideration.
Relative positions on the right-hand side of matching patterns are always of the form {i1,i2,} with non-negative integers ik. Examples of position patterns include {} for exact position of matched subexpression, _ for any relative position, {___,0} for heads and so on.
"OuterMode" and "InnerMode" allow for matching criteria to match either any or all of the corresponding subexpressions.
Patterns may come in form of a constraint specified using Except.

Examples

Basic Examples (13) 

Find all subexpressions:

In[1]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x]]]
Out[1]=

Specify level:

In[2]:=
ResourceFunction["SubexpressionPositions"][f[x, g[x, y], h[z]], {2}]
Out[2]=

Use explicit positions:

In[3]:=
ResourceFunction["SubexpressionPositions"][
 f[x, g[x, y, z]], {{2, 2 ;; -1}}]
Out[3]=

Find subexpressions that match a pattern:

In[4]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x]], "InnerMatch" -> x -> {}]
Out[4]=
In[5]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x]], "OuterMatch" -> x -> {}]
Out[5]=

Find subexpressions with any inner expression matching a specified pattern:

In[6]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x], h[z]], "InnerMatch" -> x -> _]
Out[6]=

Find subexpressions with any outer expression matching a pattern:

In[7]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x]], "OuterMatch" -> _g -> _]
Out[7]=

Find subexpressions that have any inner expression matching a specified pattern and relative position:

In[8]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x], h[x, y]], "InnerMatch" -> y -> {2}]
Out[8]=

Find subexpressions that have any outer expression matching a specified pattern and are positioned at given relative position to it:

In[9]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x], g[x, y]], "OuterMatch" -> _g -> {2}]
Out[9]=

Find subexpressions with any inner subexpression not matching a specified pattern:

In[10]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x]], "InnerMatch" -> Except[x] -> _]
Out[10]=

Find subexpressions with all inner subexpressions not matching a specified pattern:

In[11]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, x]], "InnerMatch" -> Except[x] -> _, "InnerMode" -> All]
Out[11]=

Find subexpressions with all outer expressions matching a specified pattern:

In[12]:=
ResourceFunction["SubexpressionPositions"][f[x, f[y, x], g[x]], "OuterMatch" -> _f -> _, "OuterMode" -> All]
Out[12]=

Find subexpressions with combined outer and inner matching patterns:

In[13]:=
ResourceFunction[
 "SubexpressionPositions"][{f[x, g[y]], f[a, b], f[h[1], 2], g[x, y], f[a, c[b]]}, "OuterMatch" -> _f -> {2}, "InnerMatch" -> _ -> {1}]
Out[13]=

Find specific heads:

In[14]:=
ResourceFunction[
 "SubexpressionPositions"][{f[x, g[y]], f[a, b], f[h[1], 2], g[x, y], f[a, c[b]]}, "OuterMatch" -> _g -> {___, 0}]
Out[14]=

Scope (3) 

Use Unevaluated to delay evaluation:

In[15]:=
ResourceFunction["SubexpressionPositions"][Unevaluated[1 + (2 + 3)], "InnerMatch" -> _Plus -> _]
Out[15]=

Specify an explicit list of positions with use of All and Span with UpTo:

In[16]:=
ResourceFunction["SubexpressionPositions"][
 Array[a[##] &, {2, 4, 8}], {{2}, {1, ;; UpTo[6]}, {All, 4, UpTo[10] ;; ;; -1}}]
Out[16]=

Return only given number of subexpressions:

In[17]:=
ResourceFunction["SubexpressionPositions"][{a, b, c, d}, All, 2]
Out[17]=

Options (6) 

OuterMode (2) 

Find subexpressions with all outer expressions matching a given pattern. Positions {1} and {1,1} corresponding to g[x] and x are not present due to having an outer expression matching _g:

In[18]:=
ResourceFunction["SubexpressionPositions"][f[g[x], h[y]], "OuterMatch" -> Except[_g -> _], "OuterMode" -> All]
Out[18]=

Find subexpressions matching outer expression with relative position. Positions {2} and {2,2} corresponding to g[y,z] and z are not present because they both have relative position {2}:

In[19]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, z]], "OuterMatch" -> Except[_ -> {2}], "OuterMode" -> All]
Out[19]=

InnerMode (2) 

Find subexpressions having all inner expressions matching a given pattern. Positions {2} and {2, 1} of expressions g[y] and y, respectively, are not present due to both having an inner expression matching y:

In[20]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y]], "InnerMatch" -> Except[y -> _], "InnerMode" -> All]
Out[20]=

Find subexpressions having all inner expressions matching any but the given pattern and relative position. Position {2} corresponding to g[y,z] is not present because it has the inner expression matching y at relative position {1}:

In[21]:=
ResourceFunction["SubexpressionPositions"][f[x, g[y, z], y], "InnerMatch" -> Except[y -> {1}], "InnerMode" -> All]
Out[21]=

Complement (1) 

Take a complement to the provided criteria:

In[22]:=
ResourceFunction["SubexpressionPositions"][f[g[x], h[y]], "InnerMatch" -> x -> _, "Complement" -> True]
Out[22]=

Heads (1) 

Ignore heads:

In[23]:=
ResourceFunction["SubexpressionPositions"][f[x], Heads -> False]
Out[23]=

Applications (2) 

Ignore subexpressions of patterns, conditions and pattern tests, except pattern variables themselves:

In[24]:=
ResourceFunction["SubexpressionPositions"][f[x_?p, y_ /; q[y]],
 "OuterMatch" -> Except[((_Pattern | _Condition) -> {__}) | (_PatternTest -> {Except[
        1], ___})],
 "OuterMode" -> All,
 Heads -> False]
Out[24]=

Find subexpressions of list elements together with labeled elements:

In[25]:=
ResourceFunction[
 "SubexpressionPositions"][{Labeled[x, "x"], y, f[x], {g[x, y], Labeled[z, "z"]}}, "OuterMatch" -> (_List -> {_}) | (_Labeled -> {1}), "InnerMatch" -> Except[_Labeled | _List -> {}], "InnerMode" -> All, Heads -> False]
Out[25]=

Properties and Relations (1) 

SubexpressionPositions combines Position and Extract in a convenient way to filter results by relative subexpression positions:

In[26]:=
ResourceFunction["SubexpressionPositions"][{f[x], y, f[z, a], b, f[]},
  "OuterMatch" -> _f -> {1}]
Out[26]=
In[27]:=
With[{expr = {f[x], y, f[z, a], b, f[]}},
 KeyMap[Append[1]]@
  DeleteMissing@
   Map[Quiet@Check[Extract[#, {1}], Missing[]] &]@
    Select[MatchQ[_f]]@
     AssociationMap[First@Extract[expr, {#}] &, Position[expr, _]]
 ]
Out[27]=

Version History

  • 1.2.0 – 13 May 2022
  • 1.1.0 – 28 March 2022
  • 1.0.0 – 21 December 2021

Related Resources

License Information