Clojure不一致会在函数执行期间导致Clojure
Clojure问题 我用clojure编写了以下函数: 在第一个循环中,它迭代一个映射列表并创建一个映射。 然后第二个循环迭代一个列表,匹配先前创建的映射中的数据 和一个向量,并返回一个新的映射。但是,使用相同数据的不同运行会产生 净结果不同。见下文Clojure不一致会在函数执行期间导致Clojure,clojure,Clojure,Clojure问题 我用clojure编写了以下函数: 在第一个循环中,它迭代一个映射列表并创建一个映射。 然后第二个循环迭代一个列表,匹配先前创建的映射中的数据 和一个向量,并返回一个新的映射。但是,使用相同数据的不同运行会产生 净结果不同。见下文 (defn resolve-case-per-period "Constructs a map by matching data existing in input parameter vectors" [dd case-details p
(defn resolve-case-per-period
"Constructs a map by matching data existing in input parameter vectors"
[dd case-details periods]
(let [cases ((fn [in]
(loop [case-details in, result-map {}]
(if (= (count case-details) 0)
result-map
(recur (rest case-details)
(assoc result-map
(:priority (first case-details))
(:caseid (first case-details)))))))
case-details)
periods periods]
(info "Mapping cases to periods step 1 completed " cases)
(loop [periods periods, result-map {}]
(if (= (count periods) 0)
result-map
(recur (rest periods)
(conj result-map
{ (str (:period (first periods)))
(get cases (:priority (first periods)))}))))))
返回的输出是如下所示的映射:
{31-10-10 20 10020101030122036M, 31-10-10 10 10020101030122036M, 31-10-10 21 10020101030122036M, 30-10-10 21 10020101030200157M, 31-10-10 00 10020101030122036M, 31-10-10 11 10020101030122036M, 31-10-10 22 10020101031112152M, 30-10-10 22 10020101030122036M, 31-10-10 01 10020101030122036M, 31-10-10 12 10020101030122036M, 30-10-10 23 10020101030122036M, 31-10-10 02 10020101030122036M, 31-10-10 13 10020101030122036M, 31-10-10 03 10020101030122036M, 31-10-10 14 10020101030122036M, 31-10-10 04 10020101030122036M, 31-10-10 15 10020101030122036M, 31-10-10 05 10020101030122036M, 31-10-10 16 10020101030122036M, 31-10-10 06 10020101030122036M, 31-10-10 17 10020101030122036M, 31-10-10 07 10020101030122036M, 31-10-10 18 10020101030122036M, 31-10-10 08 10020101030122036M, 31-10-10 19 10020101030122036M, 31-10-10 09 10020101030122036M}
使用相同的参数执行函数有时会产生
{31-10-10 20 nil, 31-10-10 10 nil, 31-10-10 21 nil, 30-10-10 21 nil, 31-10-10 00 nil, 31-10-10 11 nil, 31-10-10 22 nil, 30-10-10 22 nil, 31-10-10 01 nil, 31-10-10 12 nil, 30-10-10 23 nil, 31-10-10 02 nil, 31-10-10 13 nil, 31-10-10 03 nil, 31-10-10 14 nil, 31-10-10 04 nil, 31-10-10 15 nil, 31-10-10 05 nil, 31-10-10 16 nil, 31-10-10 06 nil, 31-10-10 17 nil, 31-10-10 07 nil, 31-10-10 18 nil, 31-10-10 08 nil, 31-10-10 19 nil, 31-10-10 09 nil}
如果我们不知道您的数据(函数输入)是什么样子,则很难回答您的问题,但有几点:
dd
从未在函数中使用,因此您可以将其删除let
中执行的部分分解为另一个函数。这也将使repl的测试和实验更加容易periods
重新映射到periods
没有任何效果,所以请去掉它let
中隐藏了大量的局部变量(case details
,在loop
中隐藏了periods
),这可能会造成混乱,我建议不要这样做李>
老实说,我不明白这个Clojure函数如何负责提供不同的输出,您是否绝对确定输入是相同的?作为第一种情况下的观察,你会得到值的大小数,所以我猜在第二种情况下,一些无法处理大小数的东西与数据接触。但是我看不出在您提供的函数中会发生这种情况。此函数中的所有内容都是确定的和纯粹的(除了
info
调用,这不重要),因此每次都应该返回相同的内容。您没有提供任何示例输入,因此我无法反驳此假设
代码很难阅读,没有上下文,我真的不明白你在做什么。但我在几次重构过程中仔细检查了您的代码,试图让它更清楚地了解发生了什么。希望这能帮助其他正在阅读的人,甚至让你更清楚你的问题所在
弗斯特
删除所有疯狂的格式和无意义的变量复制,并使用seq
而不是测试count=0
(defn resolve-case-per-period
"Constructs a map by matching data existing in input parameter vectors"
[dd case-details periods]
(let [cases (loop [case-details case-details, result-map {}]
(if (seq case-details)
(recur (rest case-details)
(assoc result-map
(:priority (first case-details))
(:caseid (first case-details))))
result-map))]
(info "Mapping cases to periods step 1 completed " cases)
(loop [periods periods, result-map {}]
(if (seq periods)
(recur (rest periods)
(assoc result-map
(str (:period (first periods)))
(get cases (:priority (first periods)))))
(do (info "Mapping cases to periods step 2 completed " result-map)
result-map)))))
第二
分解结构和if let而不是基本关键字查找、if和seqs:
(defn resolve-case-per-period
"Constructs a map by matching data existing in input parameter vectors"
[dd case-details periods]
(let [cases (loop [case-details case-details, result-map {}]
(if-let [[{:keys [priority case-id]} & more] (seq case-details)]
(recur more
(assoc result-map priority caseid))
result-map))]
(info "Mapping cases to periods step 1 completed " cases)
(loop [periods periods, result-map {}]
(if-let [[{:keys [period priority]} & more] (seq periods)]
(recur more
(assoc result-map
(str period)
(get cases priority)))
(do (info "Mapping cases to periods step 2 completed " result-map)
result-map)))))
第三
在这一点上,我们终于清楚了,我们只是在一个序列上进行迭代,并在执行过程中建立一个结果值,因此我们可以放弃所有的first/rest废话,只需使用reduce
为我们遍历该序列:
(defn resolve-case-per-period
"Constructs a map by matching data existing in input parameter vectors"
[dd case-details periods]
(let [cases (reduce (fn [result-map {:keys [priority case-id]}]
(assoc result-map priority caseid))
{}, case-details)]
(info "Mapping cases to periods step 1 completed " cases)
(reduce (fn [result-map {:keys [period priority]}]
(assoc result-map
(str period)
(get cases priority)))
{}, periods)))
我真的很喜欢您展示如何多次传递代码,每次都进行改进的方式。谢谢你抽出时间。我建议从原始函数的参数列表中删除
dd
。AFAICS它没有在任何地方使用。谢谢你的详尽回答。谢谢你的详尽回答。第一个数据结构case details是一个包含映射数据结构的列表,如下所示{:caseid1002010101029093512m,:exectime 29-oct-2010 09:35:17,:priority 30856568000M,:studymodeid 11M}。第二个参数periods是另一个列表,其中包含以下实例{:period 29-10-1021,:priority 30851039000M}。我想做的是用从第二个列表中提取的key:period和从第一个列表中提取的value:caseid构建一个映射。我仍然有同样的问题。两次连续运行产生以下结果:lein run 20-10-2010 1021 141954 619 INFO quartzTest.dao[main]检索案例列表当天的4个案例1021 141954 729 INFO quartzTest.dao[main]检索周期和相应的最新执行时间:25 1021 141954 812 INFO quartzTest.utils[main]完成每个周期的案例解析{20-10-10 20 nil,…}和lein运行21-10-2010 1021 142111 154 INFO quartzTest.dao[main]检索案例列表当天的4个案例1021 142111 317 INFO quartzTest.utils[main]完成每个周期的案例解析{21-10-10 10 1002010101020111632M…}如果您在答案中遇到一些棘手的问题,请不要讨论,Clojure不同于更多的过程语言,因此它可能更难开始。但是这些差异有很好的原因,我相信如果你坚持一点,你会看到好处。