【问题标题】:Clojure - Is it possible to increment a variable within a doseq statement?Clojure - 是否可以在 doseq 语句中增加变量?
【发布时间】:2015-12-14 16:43:42
【问题描述】:

我正在尝试遍历给定目录中的文件列表,并将递增变量 i = {1,2,3.....} 添加到它们的名称中。

这是我用于遍历文件并更改每个文件名的代码:

(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

我不知道如何在doseq 迭代每个文件时增加i。或者,是否有更好的循环来达到预期的结果?

【问题讨论】:

  • 你为什么要让变量的范围超出它的操作范围?
  • def 创建一个* var 正如 Charles Duffy 指出的那样,这是一个超出函数运行范围的*值,更重要的是,如果这样做通常是错误的你想要突变。此外,clojure 中惯用的做法是完全消除突变的直接使用(如下面的回答所示)。
  • 谢谢您的解释
  • 您可能会发现这段代码很有帮助:paste.ubuntu.com/6981825

标签: clojure


【解决方案1】:

使用file-seqmap-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]))))

map-indexed 中的函数更改为重命名,您就完成了。 pdf文件的示例输出:

([0 #<File /home/eduard/Downloads/some.pdf>] ...)

【讨论】:

  • 谢谢你——当你发现这个时,我实际上正在寻找地图索引来修改我自己的答案。 :)
  • 请注意,file-seq 是递归的,也会返回子目录中的文件。
  • 有没有办法让索引以 0 以外的值开始?
  • @YechielLabunskiy 你可以(inc i) 在函数内部进行地图索引。我想你已经得到了这个答案:)
【解决方案2】:

这是我想到的第一个方法。这并不理想,但肯定比问题提出的更惯用。

(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!))

请注意,实际执行重命名的工作与迭代文件的工作是分开的。一般来说,拥有大量小功能比拥有少量大功能要好,并且使这些功能可重用/独立,除非您选择一起使用它们甚至更好。

【讨论】:

  • 请注意,这一切都是即兴写的,没有经过测试,所以肯定不是完美的——但目标是展示成语/良好做法。
  • 在这种情况下,遵循成语是否真的很重要,或者我也可以使用突变,但你只是想向我展示做同样的习惯方式?
  • @YechielLabunskiy,使用 vars 进行突变会导致现实世界的错误和性能问题。正确使用习语并不总是很重要,但初始代码存在实际错误(例如,想想如果同时从两个线程调用它会发生什么)。
最近更新 更多