How to perform a depth-first preorder traversal of an expression?

I am aware of two general methods.

ReplaceAll

The only general purpose function I am aware of that visits depth-first preorder is ReplaceAll. One can "scan" a given function such as Print as a side-effect by using either PatternTest or Condition, both of which only match if the return is explicitly True.

{{1, {2, 3}}, {4, 5}} /. _?Print -> Null;

{{1,{2,3}},{4,5}}
List
{1,{2,3}}
List
1
{2,3}
List
2
3
{4,5}
List
4
5

List is printed because ReplaceAll includes Heads whereas Scan by default does not.

We cannot use the level specification of Span but we can use patterns. For example:

{{1, {2, 3}}, {4, 5}} /. {_, _} ? Print -> Null;

{{1,{2,3}},{4,5}}
{1,{2,3}}
{2,3}
{4,5}

Recursive function

This can be done using a recursive function, the purest form of which is:

(Print@#; #0 ~Scan~ #)& @ {{1, {2, 3}}, {4, 5}}

{{1,{2,3}},{4,5}}
{1,{2,3}}
1
{2,3}
2
3
{4,5}
4
5

Though not as fast as ReplaceAll this method can be extended more generally, for example to accept a level specification:

preorderScan[f_, expr_, {L1_, L2_}] :=
 Module[{rec},
  rec[n_][ex_] := (If[n >= L1, f@ex]; rec[n + 1] ~Scan~ ex);
  rec[n_ /; n > L2][_] = Null;
  rec[0][expr]
 ]

preorderScan[Print, {{1, {2, 3}}, {4, 5}}, {1, 2}]

{1,{2,3}}
1
{2,3}
{4,5}
4
5

(The function above is an illustration and not intended for reuse. It does not accept all forms of the standard levelspec and it makes no attempt to hold expressions unevaluated. If requested I can post a more lengthy version that does both.)


Here is a version that uses an explicit stack to avoid recursion.

depthFirstPreorder[expr_] := Module[
  {stack = {expr, {}}, el = expr},
  Reap[
    While[stack =!= {},
      {el, stack} = stack;
      Sow[el];
      If[Not[AtomQ[el]],
       Do[stack = {el[[j]], stack}, {j, Length[el], 1, -1}]];
      ];
    ][[2, 1]]
  ]

The customary example:

expr = {{1, {2, 3}}, {4, 5}};

depthFirstPreorder[expr]

(* Out[16]= {{{1, {2, 3}}, {4, 5}}, {1, {2, 3}}, 1, {2, 3}, 2, 3, {4, 
  5}, 4, 5} *)

Don't know where this should fit. Playing around, this could be a more general approach to the traversal problem. It's probably not best for those traversals that can be done in other ways. Specifically, it has to create the list of indices all at once so it's not memory efficient as Scan

Module[{tag}, 
 generalScan[fun_, expr_, sortingFun_: RandomSample] := 
  Extract[Unevaluated@expr, If[# === {}, fun[expr]]; #, fun] &~Scan~
   sortingFun[
    Reap[MapIndexed[tag, Hold[expr], Infinity, Heads -> True] /. 
       tag[_, {1, in___}] /; Sow[{in}, tag] :> Null, tag][[-1, 1]]]]

This takes a third argument that makes you sort the list of indices to traverse. Defaults to RandomSample (hihihi)

expr = {{{1, {2}}}, {3, {4}}};

(* Random *)
generalScan[Print, expr]

(* Breadth-first *)
generalScan[Print, expr, Sort]

(* Breadth-first right-left *)
generalScan[Print, expr, SortBy[#, Minus] &]

(* Depth-first preorder *)
generalScan[Print, expr, Part[#, Ordering[PadRight[#]]] &]

...

It could be used for other purposes such as traversing a part of a tree. This would only traverse the leftmost branch

generalScan[Print, expr, Cases[#, {1 ..}] &]