Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure - Convert File Path to Tree

Tags:

tree

clojure

I am fairly new to Clojure and I am struggling with how I can use a file path to create a tree in Clojure. I get all the files under a directory using file-seq and store them in files. The input is a file path like so:

resources/data/2012/05/02/low.xml
resources/data/2012/05/01/low.xml

I can get all the individual names of the folders and files using this:

(for [x files] 
 (if (.contains (.getPath x) ".json")
  (for [y (str/split (.getPath x) #"\\")] y)))

This gives me lists of all the folders but then I don't know how I can combine them into 1 list to create a tree structure. If any answer could explain how their code works as well, to assist with learning. The desired output for these 2 inputs would be:

(resources (data (2012 (05 (02 (low.xml)) (01 (low.xml))))))
like image 627
JForth Avatar asked Aug 20 '26 05:08

JForth


1 Answers

what you would need to build trees is something like this:

(defn as-tree [data]
  (map (fn [[k vs]] (cons k (as-tree (keep next vs))))
       (group-by first data)))

given a list of parsed paths (or in general any sequences), it would create your structure:

user> (as-tree [["resources" "data" "2012" "05" "02" "low.xml"]
                ["resources" "data" "2012" "05" "01" "aaa.xml"]
                ["resources" "data" "2012" "05" "02" "high.xml"]
                ["resources" "data" "2012" "05" "01" "xsxs.xml"]
                ["resources" "data" "2012" "06" "01" "bbb.xml"]
                ["resources" "data" "2012" "05" "01" "ccc.xml"]
                ["resources" "data" "2012" "02" "some.xml"]
                ["resources" "data" "2012" "01" "some2.xml"]
                ["other-resources" "data" "2015" "10" "some100.xml"]])

;; (("resources" 
;;   ("data" 
;;     ("2012" 
;;       ("05" 
;;         ("02" ("low.xml") 
;;               ("high.xml")) 
;;         ("01" ("aaa.xml") 
;;               ("xsxs.xml") 
;;               ("ccc.xml"))) 
;;       ("06" 
;;         ("01" ("bbb.xml"))) 
;;       ("02" ("some.xml")) 
;;       ("01" ("some2.xml"))))) 
;;  ("other-resources" ("data" ("2015" ("10" ("some100.xml"))))))

so in your case it could look like this (tree for .clj files in project):

(require '[clojure.string :as cs])
(import 'java.io.File)

(->> (File. ".")
     file-seq
     (map #(.getPath %))
     (filter #(cs/ends-with? % ".clj"))
     (map #(cs/split % (re-pattern File/separator)))
     as-tree
     first)

;;=> ("." 
;;     ("src" 
;;       ("playground" 
;;         ("core.clj"))) 
;;     ("test" 
;;       ("playground" 
;;         ("core_test.clj"))) 
;;     ("project.clj"))
like image 158
leetwinski Avatar answered Aug 22 '26 17:08

leetwinski