March 9, 2010 spout

Creating a Lazy Sequence of Directory Descendants in C#

My dear friend Craig Andera posted an implementation of a function that descends into a directory in a lazy” manner, i.e. you get the first descendant back right away and not after all descendants have been calculated. His implementation was in Clojure, a Lisp variant that runs on the Java VM:

(import [java.io File])

(defn dir-descendants [dir]
  (let [children (.listFiles (File. dir))]
    (lazy-cat
     (map (memfn getPath) (filter (memfn isFile) children))
     (mapcat dir-descendants
      (map (memfn getPath) (filter (memfn isDirectory) children))))))

Craig was happy with this function because, even though it was a mind-bender to write,” it’s easy to read and because C# would almost certainly be at least somewhat more verbose.”

Taking this as a challenge, I rewrote this program in C#, maintaining the laziness:

using System.IO;
using System.Collections.Generic;

namespace ConsoleApplication1 {
    class Program {
        static IEnumerable<string> GetDirectoryDecendants(string path) {
            foreach (var file in Directory.GetFiles(path)) { yield return file; }
            foreach (var directory in Directory.GetDirectories(path)) {
                foreach (var file in GetDirectoryDecendants(directory)) { yield return file; }
            }
        }
    }
}

The key hit here is the use of yield return” which lets me return elements of an IEnumerable as I calculate them. This took me 5 minutes to write, my mind is straight and I find it fairly easy to read. I’ll let you decide on the relative verbosity of each implementation.