Loops 有没有更好的方法在clojure中编写嵌套循环?
有没有更好的方法在clojure中实现嵌套循环 作为一名初学者,我编写了这个嵌套循环代码,用于比较日内日期之间的差异 将其与java中使用for或while的嵌套循环进行比较Loops 有没有更好的方法在clojure中编写嵌套循环?,loops,clojure,Loops,Clojure,有没有更好的方法在clojure中实现嵌套循环 作为一名初学者,我编写了这个嵌套循环代码,用于比较日内日期之间的差异 将其与java中使用for或while的嵌套循环进行比较 (def my-vector [{:course-type "clojure" :start-date "2021-01-25" :end-date "2021-02-06"}
(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)
学习在Clojure中编程需要学习以不同的方式思考,因为人们习惯于在命令式编程中使用的技巧和技术在Clojure中可能不起作用。例如,在一个嵌套循环中,如上面所示,您想做什么?您正在尝试将
mycourses
的所有元素相互匹配,并进行一些处理。让我们定义一个函数,它将返回集合1中所有元素的组合:
这是一个非常简单的函数,它将集合中的所有元素相互匹配,并返回累积的对。例如,如果您调用
(combos [1 2 3])
你会回来的
([1 1] [1 2] [1 3] [2 1] [2 2] [2 3] [3 1] [3 2] [3 3])
(["abc" "abc"] ["abc" 1] ["abc" [0 9]] [1 "abc"] [1 1] [1 [0 9]] [[0 9] "abc"] [[0 9] 1] [[0 9] [0 9]])
这将适用于任何集合。如果调用组合
作为
(combos '("abc" 1 [0 9]))
你会回来的
([1 1] [1 2] [1 3] [2 1] [2 2] [2 3] [3 1] [3 2] [3 3])
(["abc" "abc"] ["abc" 1] ["abc" [0 9]] [1 "abc"] [1 1] [1 [0 9]] [[0 9] "abc"] [[0 9] 1] [[0 9] [0 9]])
所以我想你能看到我们要去哪里。您不必对集合运行嵌套循环,只需创建元素组合的集合并对这些组合运行简单循环即可:
(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)))))
但是,如果我们不想考虑一个课程与自己相匹配的情况,那该怎么办呢?在这种情况下,另一个只返回所需案例的函数很有用:
(defn different-combos [c] ; all combinations where [1] <> [2]
(filter #(not= (% 0) (% 1)) (combos c)))
(定义不同的组合[c];所有组合,其中[1][2]
(过滤器#(非=(%0)(%1))(组合c)))
使用最适合你的东西
1关于这里,Clojure专家可能会尖叫“不!不!使用!”。在教学时,我喜欢给学生举一些有用的例子,让他们可以看到、阅读和学习。YMMV.以下是我将如何编写上述代码,从我最喜欢的代码开始。我已经包括了一些单元测试来说明代码中发生了什么:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:import
[java.time LocalDate]))
(defn days-between
"Find the (signed) interval in days between two LocalDate strings."
[localdate-1 localdate-2]
(.between java.time.temporal.ChronoUnit/DAYS
(LocalDate/parse localdate-1)
(LocalDate/parse localdate-2)))
(dotest ; from tupelo.test
(is= -5 (days-between "2021-01-25" "2021-01-20"))
(is= 5 (days-between "2021-01-25" "2021-01-30")))
(defn course-pairs-with-30-day-gap
"Return a list of course pairs where the start date of the first course
is at least 30 days after the end of the second."
[courses]
(for [c1 courses
c2 courses
:let [start-1 (:start-date c1)
end-2 (:end-date c2)
gap-days (days-between end-2 start-1)]
:when (< 30 gap-days)]
[(:course-type c1) (:course-type c2) gap-days]))
在输出中,我留下了课程-1、课程-2的名称,以及天数间隔,以验证计算是否符合预期。当然,这可以修改或扩展以用于生产
在clojure中,我们通常使用预先存在的函数,如for
(技术上是一个宏),而不是像loop/recur
这样的低级工具。修饰符:let
和:when
使它们在分析和转换数据结构时更强大
请看这个,,
尤其是像《获取Clojure》和《Clojure备忘单》这样的书。是的,我必须换一种思路,组合是获取日期对的好方法。精化将是[{Clojure,r}{r,python}{python,java}]的组合。为了回答您的问题,数据将按学生在2020-2021年完成的课程的周期顺序排列。Clojure是最近的,java是最老的。因此,我共享的代码以某种方式对向量进行迭代,它将比较像[{clojure,r}{r,python}{python,java}]这样的日期,并找出它们之间是否有任何差距。就像在java中,我试图比较索引[I]和索引[I+1]的值。另一个选项,如果总是想忽略for的某些结果,是使用
:当中的表达式用于的绑定表达式时,而不是筛选的结果用于。感谢Alan提供的方法!!!