有没有更好的方法在 clojure 中实现嵌套循环?
作为初学者,我编写了这段嵌套循环代码,用于比较以天为单位的日期之间的差异。
将此与 Java 中使用 for 或 while 的嵌套循环进行比较。
(def my-vector [{:course-type "clojure"
:start-date "2021-01-25"
:end-date "2021-02-06"}
{:course-type "r"
:start-date "2021-01-15"
:end-date "2021-02-06"}
{:course-type "python"
:start-date "2020-12-05"
:end-date "2021-01-05"}
{:course-type "java"
:start-date "2020-09-15"
:end-date "2020-10-20"}
])
(defn find-gap-in-course [mycourses]
(println "Finding gap between dates....")
(loop [[course1 & mycourses] mycourses]
(loop [[course2 & mycourses] mycourses]
(when (and
(and (not-empty course1) (not-empty course2))
(> (-> java.time.temporal.ChronoUnit/DAYS
(.between
(LocalDate/parse (course2 :end-date))
(LocalDate/parse (course1 :start-date)))) 30))
(println "Dates evaluated are =" (course2 :end-date) (course1 :start-date))
(println "Gap of > 30 days between dates ="
(-> java.time.temporal.ChronoUnit/DAYS
(.between
(LocalDate/parse (course2 :end-date))
(LocalDate/parse (course1 :start-date)))))
(do true)))
(do false)
(if course1 (recur mycourses))))
(find-gap-in-course my-vector)
Run Code Online (Sandbox Code Playgroud)
学习在 Clojure 中编程需要一个人学会以不同的方式思考,因为人们习惯于在命令式编程中使用的技巧和技术在 Clojure 中可能无法很好地发挥作用。例如,在嵌套循环中,如上面所示,您要做什么?您正在尝试将 的所有元素相互匹配mycourses并进行一些处理。因此,让我们定义一个函数,该函数返回集合1中元素的所有组合:
(defn combos[c] ; produce all combinations of elements in a collection
(for [x c y c] (vector x y)))
Run Code Online (Sandbox Code Playgroud)
这是一个非常简单的函数,它将集合的所有元素相互匹配并返回累积的配对。例如,如果您调用
(combos [1 2 3])
Run Code Online (Sandbox Code Playgroud)
你会回来的
([1 1] [1 2] [1 3] [2 1] [2 2] [2 3] [3 1] [3 2] [3 3])
Run Code Online (Sandbox Code Playgroud)
这将适用于任何集合。如果您调用combos为
(combos '("abc" 1 [0 9]))
Run Code Online (Sandbox Code Playgroud)
你会回来的
(["abc" "abc"] ["abc" 1] ["abc" [0 9]] [1 "abc"] [1 1] [1 [0 9]] [[0 9] "abc"] [[0 9] 1] [[0 9] [0 9]])
Run Code Online (Sandbox Code Playgroud)
所以我想你可以看到我们要去哪里。无需对集合运行嵌套循环,您只需创建元素组合的集合并在这些组合上运行简单的循环即可:
(defn find-gap-in-course [mycourses]
(loop [course-combos (combos mycourses)]
(let [combi (first course-combos)
[course1 course2] combi]
; ...processing of course1 and course2 here...
(recur (rest mycourses)))))
Run Code Online (Sandbox Code Playgroud)
但是如果我们不想考虑课程与自身匹配的情况呢?在这种情况下,另一个仅返回所需案例的函数很有用:
(defn different-combos [c] ; all combinations where [1] <> [2]
(filter #(not= (% 0) (% 1)) (combos c)))
Run Code Online (Sandbox Code Playgroud)
使用最适合您的方法。
1关于这里的 Clojure 行家可能会尖叫“不!不!使用clojure.math.combinatorics!”。在教学时,我喜欢给出有用的例子,学生可以看到、阅读和学习。天啊。