前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >命令行中 tree 的多重实现

命令行中 tree 的多重实现

作者头像
lambeta
发布2018-08-17 11:29:44
6160
发布2018-08-17 11:29:44
举报
文章被收录于专栏:编舟记

解题思路

  1. 利用递归,将目录转换成 {:name: ".", :children: []} 结构
  2. 对于第一层目录名,前缀装饰成 T_branch = "├── "或者 L_branch = "└── "
  3. 对于子目录,前缀装饰成 I_branch = "│ "或者SPACER = " " 举例如下:
代码语言:javascript
复制
.
├── 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 实现

代码语言:javascript
复制
#!/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
import functools as fp

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

def _children(path):
    return map(lambda filename: tree_format(path, filename), os.listdir(path))

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

def render_tree(tr):
    name = tr['name']
    children = tr['children']
    return [name] + fp.reduce(lambda l, r: l + r,
                              map(lambda arg: render(len(children))(*arg),
                                  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 = [prefix_rest + t for t in tr[1:]]
        return [head] + tail
    return prefix

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

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

Clojure 实现

代码语言:javascript
复制
(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 实现

代码语言:javascript
复制
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(path string) []entry {
    result := []entry{}
    files, _ := ioutil.ReadDir(path)
    for _, f := range files {
        result = append(result, Tree(path, f.Name()))
    }

    return result
}

func Tree(parent, dirName string) 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 实现

代码语言:javascript
复制
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

代码语言:javascript
复制
import java.io.File

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

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

fun children(path: File): List<Entry> {
    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<Entry>())
}

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

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

fun prefix(size: Int): (Int, Entry) -> List<String> {
    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

代码语言:javascript
复制
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

Elixir

代码语言:javascript
复制
#!/usr/bin/env elixir

defmodule Tree do
  def main([dir | _]) do
    dir |> tree_format |> render_tree |> Enum.join("\n") |> IO.puts
  end

  defp children(path) do
    if (path |> File.dir?) do
      File.ls!(path) |> Enum.map(fn f -> tree_format(path, f) end)
    else
      []
    end
  end

  defp tree_format(parent_dir \\ ".", dir_name) do
    %{:name => dir_name, :children => Path.join(parent_dir, dir_name) |> children}
  end

  defp decorate(is_last?, [parent | children]) do
    prefix_first = (if (is_last?), do: "└── ", else: "├── ")
    prefix_rest = (if (is_last?), do: "    ", else: "│   ")
    [prefix_first <> parent | children |> Enum.map(fn child -> prefix_rest <> child end)]
  end

  defp render_tree(%{name: dir_name, children: children}) do
    [dir_name 
     | children 
     |> Enum.with_index(1)
     |> Enum.map(fn {child, index} -> decorate(length(children) == index, render_tree(child)) end) 
     |> List.flatten]
  end

end

Tree.main(System.argv)

$ elixir tree.exs .
.
├── tree.py
├── files.py
├── lists.py
├── tuples.py
├── resources
│   └── README.md
├── recursion.py
└── data
    ├── output.txt
    └── data.txt
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.02.24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 解题思路
  • python 实现
  • Clojure 实现
  • Golang 实现
  • NodeJS 实现
  • Kotlin script
  • Scala
  • Elixir
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档