# Code Golf: Directory Tree -> Tree

Contest (!): In the language of your choice, write a program that will traverse the directory tree of a given directory and output a tree (i.e., an array of arrays) corresponding to it. Assume the directory is a predefined variable D. Smallest character count wins.

Rules:

• You must use recursion
• See Rules

Note: Assume that there are no recursion depth limits. In other words, your code just needs to work for sufficiently small directory trees, and in principle for larger ones.

For instance:

Directory tree is

dir1
├── dir11
│   ├── file111
│   └── file112
├── dir12
│   ├── file121
│   ├── file122
│   └── file123
├── file11
├── file12
└── file13


Output tree is

[[[],[]],[[],[],[]],[],[],[]]


First code golf here so lemme know if I'm doing something wrong.

Have fun :)

• "Rules: 1. You must use recursion 2. See rules" Ah!! HELP I'M STUCK IN AN INFINITE LOOP! Jan 8, 2014 at 7:42
• You could go by the character count, or you could go by smallest size in bytes (this way programs with unicode characters are larger than if they used pure ascii) Jan 8, 2014 at 7:43
• How deep would it traverse? Jan 8, 2014 at 7:47
• Many people would appreciate it if you instead gave an input of a file (as a path, or something else) and they could simply output it. Also, your output seems a bit hard to understand. Can you provide a test case? Rather than using an array of arrays, could we simply print each directory/file on its own line, but indented to show subfolderness? Basically, must we output in a certain format (in which case, give an example), or can we choose a format (as long as it is unambiguous)? Jan 8, 2014 at 7:48
• I'm going blind, parsing your output format. This, from someone who enjoys Lisp. Jan 8, 2014 at 8:41

# Mathematica 12021 20 Explicit recursion (thanks alephalpha for saving one char):

f=f/@__~FileNames~#&

f["~/StackExchange/dir1"]


{{{}, {}}, {{}, {}, {}}, {}, {}, {}}

TreeForm[%] Previous overcomplicated solution:

d="~/StackExchange/dir1"

f@{x___,Longest@s:{y_,___}..,z___}:=f@{x,f@Drop[{s},1,1],z}
f[FileNameSplit/@FileNames[__,SetDirectory@d;"",∞]]/.f->(#&)

• f=f/@__~FileNames~#& Jan 13, 2014 at 6:04

## Ruby, 38 chars

If you don't mind some extra whitespace in the output:

f=->n{Dir[n+'/*'].map{|c|f[c]}}
p f[D]


Example usage:

D='C:/work/dir1'
f=->n{Dir[n+'/*'].map{|c|f[c]}}
p f[D]


Output:

[[[], []], [[], [], []], [], [], []]


If I can't have the whitespace, something like this for the second line:

puts"#{f[D]}".tr' ',''


# Python 2.7, 111 chars

Takes the target path from stdin.

import os
def R(d):return[R(f)for f in[d+'/'+e for e in os.listdir(d)]if os.path.isdir(f)]
print R(raw_input())


## Powershell - 182 Char

function A([string]$b){write-host -NoNewline '['; ls -path$b|foreach{if($_.PSIsContainer){A($_.FullName)}ELSE{write-host -NoNewline $f'[]';$f=', '}};write-host -NoNewline ']'};A($D)  Fairly simple. Could be reduced by 10 characters if the commas weren't required. Takes input from$D (as stated in question), returns output on STD-Out as the example in the question went.

Really wishing aliases could use options! I'm being killed by the 'write-host -NoNewline's!

• I think it might be able to be done a little better. An more experienced golfers want to give it a crack? Jan 16, 2014 at 11:25
• I don't know if you've actually hit the target that the challenge is aiming for... but that's not a big deal since everyone who responded seems to have chosen their own interpretation. Jan 23, 2015 at 17:53
• {doh! Hit enter by accident. } That being said I'm not going to touch your foreach{} interpretation, I'm just going to point to an improvement you can make. The first powershell trick you're missing is that write-host is unnecessary, if you end your code with data in the pipeline it's written to the host. The second trick is the automagic expand and concatenate that happens within double-quotes. Finally use get-alias to identify tricks like % = foreach. Next time use a strategy that encases your results within a variable then ends by calling that variable: $a = gi$d | ls | %{}; "[\$a]" Jan 23, 2015 at 18:08

# C# 200 chars

Outputting a string, not an actual array. Takes a path as the first argument.

using D=System.IO.DirectoryInfo;class P{static string R(D d){var r="[";foreach(D e in d.GetDirectories())r+=R(e);return r+"]";}static void Main(string[] a) {System.Console.WriteLine(R(new D(a)));}}


Ungolfed:

using D = System.IO.DirectoryInfo;

class P
{
static string R(D d)
{
var r = "[";
foreach (D e in d.GetDirectories())
r += R(e);
return r + "]";
}

static void Main(string[] a)
{
System.Console.WriteLine(R(new D(a)));
}
}

• My first golf attempt, and C# is a rather verbose language. Any advice would be appreciated.
– Bob
Jan 13, 2014 at 3:56

## C++, 318 bytes

#include <cstdio>
#include <dirent.h>
#include <string>
#define s std::string
#define n e->d_name
s l(s p){s r;dirent*e;DIR*d;if(d=opendir(p.c_str())){int c=0;while(e=readdir(d))if(s("..")!=n&s(".")!=n)r+=&",["[!c++]+(e->d_type==DT_DIR?l(p+'/'+n):"")+"]";closedir(d);}return r;}main(){puts((s("[")+l(D)+"]").c_str());}


Here is a slightly ungolfed version:

#include <cstdio>
#include <dirent.h>
#include <string>

#define s std::string
#define n e->d_name

s l(s p) {
s r;
dirent*e;
DIR*d;
if (d=opendir(p.c_str())) {
int c=0;
if (s("..")!=n&s(".")!=n)
r+=&",["[!c++]+(e->d_type==DT_DIR?l(p+'/'+n):"")+"]";
closedir(d);
}
return r;
}

main() {
puts((s("[")+l(D)+"]").c_str());
}


Please notice that since -- per instructions -- D is assumed to be a predefined variable, the code does not build without somehow supplying D. Here is one way to build:

g++ -Dmain="s D=\".\";main" -o tree golfed.cpp


## Batch script - 146, 157, 152 127 bytes

set x=
:a
set x=%x%,[
cd %1
goto %errorlevel%
:0
for /f %%a in ('dir/b') do call:a %%a
cd..
:1
set x=%x:[,=[%]
cls
@echo %x:~1%


Run with:

scriptfile.cmd folderroot

• The output gets bigger on every run of this script. Jan 13, 2014 at 4:16
• Yeah, it wasn't very session friendly, but should be better now Jan 13, 2014 at 7:21