有没有更好的方法在 clojure 中编写嵌套循环?

0 loops clojure

有没有更好的方法在 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)

Bob*_*ica 5

学习在 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!”。在教学时,我喜欢给出有用的例子,学生可以看到、阅读和学习。天啊。