11
\$\begingroup\$

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 :)

\$\endgroup\$
  • 7
    \$\begingroup\$ "Rules: 1. You must use recursion 2. See rules" Ah!! HELP I'M STUCK IN AN INFINITE LOOP! \$\endgroup\$ – Justin Jan 8 '14 at 7:42
  • 1
    \$\begingroup\$ 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) \$\endgroup\$ – Justin Jan 8 '14 at 7:43
  • 1
    \$\begingroup\$ How deep would it traverse? \$\endgroup\$ – It'sNotALie. Jan 8 '14 at 7:47
  • \$\begingroup\$ 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)? \$\endgroup\$ – Justin Jan 8 '14 at 7:48
  • 3
    \$\begingroup\$ I'm going blind, parsing your output format. This, from someone who enjoys Lisp. \$\endgroup\$ – Darren Stone Jan 8 '14 at 8:41
6
\$\begingroup\$

Mathematica 120 21 20

enter image description here

Explicit recursion (thanks alephalpha for saving one char):

f=f/@__~FileNames~#&

f["~/StackExchange/dir1"]

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

TreeForm[%]

enter image description here

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->(#&)
\$\endgroup\$
  • \$\begingroup\$ f=f/@__~FileNames~#& \$\endgroup\$ – alephalpha Jan 13 '14 at 6:04
2
\$\begingroup\$

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' ',''
\$\endgroup\$
2
\$\begingroup\$

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())
\$\endgroup\$
2
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ I think it might be able to be done a little better. An more experienced golfers want to give it a crack? \$\endgroup\$ – lochok Jan 16 '14 at 11:25
  • \$\begingroup\$ 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. \$\endgroup\$ – H.R.Rambler Jan 23 '15 at 17:53
  • \$\begingroup\$ {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]" \$\endgroup\$ – H.R.Rambler Jan 23 '15 at 18:08
1
\$\begingroup\$

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[0])));}}

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[0])));
    }
}
\$\endgroup\$
  • \$\begingroup\$ My first golf attempt, and C# is a rather verbose language. Any advice would be appreciated. \$\endgroup\$ – Bob Jan 13 '14 at 3:56
0
\$\begingroup\$

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;
        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());
}

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
\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ The output gets bigger on every run of this script. \$\endgroup\$ – unclemeat Jan 13 '14 at 4:16
  • 1
    \$\begingroup\$ Yeah, it wasn't very session friendly, but should be better now \$\endgroup\$ – Robert Sørlie Jan 13 '14 at 7:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.