Tree command 的多重实现

微信扫一扫,分享到朋友圈

Tree command 的多重实现
  1. 利用递归,将目录转换成 {:name: ".", :children: []}
    结构
  2. 对于第一层目录名,前缀装饰成 T_branch = "├── "
    或者 L_branch = "└── "
  3. 对于子目录,前缀装饰成 I_branch = "│ "
    或者 SPACER = " "

    举例如下:

    .
    ├── tree.py  # 不是最后一项,所以使用 T_branch 前缀
    ├── files.py
    ├── lists.py
    ├── tuples.py
    ├── resources
    │   └── README.md # 由于其父亲不是最后一项,所以使用 I_branch 前缀
    ├── recursion.py
    └── data    # 是最后一项,所以使用 L_branch 前缀
        ├── output.txt # 由于其父亲是最后一项,所以使用 SPACE 前缀
        └── data.txt
    

python 实现

#!/usr/local/bin/python
# -*- coding: UTF-8 -*-

"""
list a directory in tree way.

children(path):
    map(lambda name: tree(path, name), listdir(path))

tree(parent, dir_name):
    if is_file(parent, dir_name):
        return {'name': dir_name, 'children': []}
    else:
        children = children(join(parent, dir_name))
        return {'name': dir_name, 'children': children}
"""
import os, sys

I_branch = "│ "
T_branch = "├── "
L_branch = "└── "
SPACER   = " "

def children(path):
    return map(lambda filename: tree(path, filename), os.listdir(path))

def tree(parent, dir_name):
    p = os.path.join(parent, dir_name)
    is_file = os.path.isfile(p) 
    the_children = [] if is_file else children(p)
    return {'name': dir_name, 'children': the_children}

def render_tree(tr):
    name = tr['name']
    children = tr['children']
    return [name] + reduce(lambda l, r: l+r, 
                           map(render(len(children)), enumerate(children)), 
                           [])

def render(length):
    def prefix((index, child)):
        is_last = index == length-1 
        prefix_first = L_branch if is_last else T_branch
        prefix_rest = SPACER if is_last else I_branch
        tr = render_tree(child)
        head = prefix_first + tr[0]
        tail = map(lambda t: prefix_rest + t, tr[1:])
        return [head] + tail
    return prefix

#print 'n'.join(render_tree(tree('', ".")))

if __name__ == "__main__":
    print 'n'.join(render_tree(tree('', sys.argv[1])))

$ python tree.py . #打印当前的目录的所有文件及子目录
.
├── tree.py
├── files.py
├── lists.py
├── tuples.py
├── resources
│   └── README.md
├── recursion.py
└── data
    ├── output.txt
    └── data.txt

Clojure 实现

(ns tree
  (:require [clojure.java.io :as io]
            [clojure.string :as str]))
(def L-branch "└── ")
(def T-branch "├── ")
(def I-branch "│   ")
(def SPACE    "    ")

(declare tree)

(defn children [path]
  (map #(tree %) (.listFiles path)))

(defn tree [dir-name]
  (let [path (io/file dir-name)
        dir? (.isDirectory path)]
    {:name (.getName path)
     :children (if dir? (children path))}))

(defn render-tree [{name :name children :children}]
  (cons name
        (mapcat (fn [child index]
                  (let [last? (= index (dec (count children)))
                        prefix-first (if last? L-branch T-branch)
                        prefix-rest (if last? SPACE I-branch)
                        sub-tree (render-tree child)]
                    (cons (str prefix-first (first sub-tree))
                          (map #(str prefix-rest %) (rest sub-tree)))))
                children
                (range))))

(defn -main [& args]
  (->> 
      (tree (first args))
      (render-tree)
      (str/join "n")
      (println)))
$ lein run -m tree .
.
├── tree.py
├── files.py
├── lists.py
├── tuples.py
├── resources
│   └── README.md
├── recursion.py
└── data
    ├── output.txt
    └── data.txt

Golang 实现

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

const (
	I_branch = "│ "
	T_branch = "├── "
	L_branch = "└── "
	SPACER   = " "
)

type entry struct {
	name     string
	children []entry
}

func (e entry)String()string {
	if len(e.children) == 0 {
		return e.name
	} else {
		s := e.name
		for _, child := range e.children {
			s += child.String()
		}

		return s
	}
}

func Children(pathstring)[]entry {
	result := []entry{}
	files, _ := ioutil.ReadDir(path)
	for _, f := range files {
		result = append(result, Tree(path, f.Name()))
	}

	return result
}

func Tree(parent, dirNamestring)entry {
	realPath := path.Join(parent, dirName)
	theChildren := []entry{}
	if f, ok := os.Stat(realPath); ok == nil {
		if f.IsDir() {
			theChildren = Children(realPath)
		}
	}
	return entry{name: dirName, children: theChildren}
}

func RenderTree(e entry)[]string {
	name := e.name
	children := e.children
	result := []string{name}

	for index, child := range children {
		subTree := RenderTree(child)
		prefixFirst := T_branch
		prefixRest := I_branch
		if index == len(children)-1 {
			prefixFirst = L_branch
			prefixRest = SPACER
		}

		result = append(result, prefixFirst+subTree[0])

		for _, sub := range subTree[1:] {
			result = append(result, prefixRest+sub)
		}
	}
	return result
}

func main() {
	fmt.Println(strings.Join(RenderTree(Tree("", os.Args[1])), "n"))
}
$ go run tree.go .
.
├── data
│   ├── data.txt
│   └── output.txt
├── files.py
├── lists.py
├── recursion.py
├── resources
│   └── README.md
├── tree.py
└── tuples.py

NodeJS 实现

const path = require('path')
const fs = require('fs')
const I_branch = '│ '
const T_branch = '├── '
const L_branch = '└── '
const SPACER   = ' '

function children(path){
    return fs.readdirSync(path).map(filename=> tree(path, filename))
}

function tree(parentDir, dirName){
    let realPath = path.join(parentDir, dirName)
    let isDir = fs.statSync(realPath).isDirectory()
    return {name: dirName, children: isDir ? children(realPath) : []}
}

function prefix(len){
    return (tr, index) => {
        let isLast = len == index + 1
        let prefixFirst = isLast ? L_branch : T_branch
        let prefixRest = isLast ? SPACER : I_branch
        let [head, ...tail]= renderTree(tr)

        return [prefixFirst + head].concat(tail.map(name=> prefixRest + name))
    }
}

function renderTree({name: name, children: children}){
    return [name]
        .concat(children
            .map(prefix(children.length))
            .reduce((l, r) => l.concat(r), []))
}

console.log(renderTree(tree('', process.argv[2])).join('n'))

$ node tree.js .
.
├── data
│   ├── data.txt
│   └── output.txt
├── files.py
├── lists.py
├── recursion.py
├── resources
│   └── README.md
├── tree.py
└── tuples.py

Kotlin script

import java.io.File

val I_branch = "│ "
val T_branch = "├── "
val L_branch = "└── "
val SPACER   = " "

data class Entry(val name: String, val children: List)

fun children(path:File): List {
    return path.listFiles().map {tree(it)}
}

fun tree(path:File): Entry {
    val isDir = path.isDirectory()
    return Entry(path.getName(), if(isDir) children(path) else listOf())
}

fun renderTree(tree:Entry): List {
    val name = tree.name
    val children = tree.children

    return listOf(name) + children.mapIndexed { i, e -> prefix(children.size)(i, e) }.fold(listOf()) {l, r -> l + r}
}

fun prefix(size:Int): (Int, Entry) -> List {
    return {index, entry ->
        val isLast = index + 1 == size
        val prefixFirst = if(isLast) L_branch else T_branch
        val prefixRest = if(isLast) SPACER else I_branch
        val subTree = renderTree(entry)

        listOf(prefixFirst + subTree.first()) + subTree.drop(1).map {t -> prefixRest + t}
    } 
}

println(renderTree(tree(File(args[0]))).joinToString("n"))

$ kotlinc -script tree.kts .
.
├── tree.py
├── files.py
├── lists.py
├── tuples.py
├── resources
│   └── README.md
├── recursion.py
└── data
    ├── output.txt
    └── data.txt

Scala

import java.io._
val I_branch = "│ "
val T_branch = "├── "
val L_branch = "└── "
val SPACER   = " "

case class Entry(name: String, children: List[Entry])

def children(path: File): List[Entry] = path.listFiles().toList.map((it: File) => tree(it))

def tree(path: File): Entry = Entry(path.getName(), if(path.isDirectory()) children(path) else List[Entry]())

def prefix(size: Int) = (index: Int, entry: Entry) => {
    val isLast = index + 1 == size
    val prefixFirst = if(isLast) L_branch else T_branch
    val prefixRest = if(isLast) SPACER else I_branch
    val subTree = renderTree(entry)
    List(prefixFirst + subTree.head) ++ subTree.tail.map(t => prefixRest + t)
}

def renderTree(tree: Entry): List[String] = {
    val name = tree.name
    val children = tree.children

    return List(name) ++ children
      .zipWithIndex
      .map({case (e: Entry, i: Int) => prefix(children.size)(i, e)})
      .fold(List[String]())((l, r) => l ++ r)
}

println(renderTree(tree(new File(args(0)))).mkString("n"))

$ scala tree.scala .
.
├── tree.py
├── files.py
├── lists.py
├── tuples.py
├── resources
│   └── README.md
├── recursion.py
└── data
    ├── output.txt
    └── data.txt

微信扫一扫,分享到朋友圈

Tree command 的多重实现

Many columns in a table

上一篇

PoC: Copy Data into Remote Process Address Space with Window Messages

下一篇

你也可能喜欢

Tree command 的多重实现

长按储存图像,分享给朋友