Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure - Is it possible to increment a variable within a doseq statement?

Tags:

clojure

I am trying to iterate over a list of files in a given directory, and add an incrementing variable i = {1,2,3.....} to their names.

Here is the code I have for iterating through the files and changing each file's name:

(defn addCounterToExtIn [d]
  (def i 0)
  (doseq [f (.listFiles (file d)) ] ; make a sequence of all files in d
    (if (and (not (.isDirectory f)) ; if file is not a directry and
             (= '(\. \i \n) (take-last 3 (.getName f))) ) ; if it ends with .in
      (fs/rename f (str d '/ i (.getName f)))))) ; add i to start of its name

I don't know how can I increment i as doseq iterates through each file. Alternatively, is there a better loop to use to achieve the desired result?

like image 996
Yechiel Labunskiy Avatar asked Dec 19 '22 17:12

Yechiel Labunskiy


2 Answers

use file-seq and map-indexed:

(require '[clojure.java.io :as io])

(dorun
  (->>
    (file-seq (io/file "/home/eduard/Downloads"))
    (filter #(re-find #".+\.pdf$" (.getName %)))
    (map-indexed (fn [i v] [i v]))))

Change function in map-indexed to rename and you're done. The sample output for pdf files:

([0 #<File /home/eduard/Downloads/some.pdf>] ...)
like image 123
edbond Avatar answered May 19 '23 00:05

edbond


This is the first approach off the top of my head. It's not ideal, but certainly more idiomatic than what the question proposes.

(def rename-one-file! [file counter]
  (if (and (not (.isDirectory file))
           (= ".in" (str (take-last 3 (.getName file)))))
      (fs/rename file (file (parent dir)
                            (str counter (.getName file)))))


(defn iterate-files-with-counter [fn dir]
  (loop [counter 0
         remaining-files (.listFiles (file dir))]
    (let [current-file (first remaining-files)]
      (fn file counter)
      (recur (+ counter 1) (rest remaining-files))))

(def add-counter-to-ext-in-dir
  (partial iterate-files-with-counter rename-one-file!))

Note that the work of actually performing the rename was split off from the work of iterating over the files. Having a large number of small functions is better than than a small number of large functions in general, and making those functions reusable / independent unless you choose to use them together is even better than that.

like image 36
Charles Duffy Avatar answered May 18 '23 22:05

Charles Duffy