clojure 中的折叠哈希函数
folding hash function in clojure
折叠哈希函数将其输入(在本例中为 int)分解为长度为 p 的片段并将这些部分相加。如果(not (= (mod input p) 0 ))
,即输入的长度不是p的倍数,最后一段可能是任意长度小于p。
到目前为止,这是我的代码:
(def firstX
(fn [x item]
(take x (str item))))
(def remX
(fn [x item]
(drop x (str item))))
(def divItemEq
(fn [a digits]
(cond (> digits (count (str a))) (a)
true (cons (list (firstX digits a)) (divItemEq (remX digits a) digits)))))
(def sumDigits
(fn [x]
(reduce + x)))
(def exItem1 76123451001214)
(print (sumDigits (divItemEq exItem1 3)))
目前无限递归(栈溢出)是因为divItemEq中的递归条件永远不满足。我试图解决这个问题导致了各种 type/casting 错误。
有什么改进的建议吗divItemEq
?
我不确定您不想使用哪些其他核心功能,但我想出了以下解决方案:
(defn chars->int [chars]
(Integer/parseInt (apply str chars)))
(defn int-partition [n count]
(loop [acc [] xs (str n)]
(if (seq xs)
(recur (conj acc (chars->int (take count xs))) (drop count xs))
acc)))
(int-partition 76123451001214 3)
;; yields
[761 234 510 12 14]
(reduce + (int-partition 76123451001214 3))
;; yields
1531
请注意,此版本并不懒惰,可能不适合大量输入。您可能希望使用 lazy-seq
.
对其进行修改
这里有很多地方需要改进,首先是使用更惯用的 defn
而不是 (def name (fn
方案。接下来是你们的名字,我觉得不太清楚。其他人指出了您使用 partition
的方向,我同意,但在下面的解决方案中,我试图保持您方法的精神。
正如您自己发现的那样,将数字转换为数字序列很有意义,因为无论如何我们都需要序列操作。那么让我们从那个开始:
(defn decimal-digits [number]
(letfn [(ddigits-helper [number result]
(if (number > 0)
(recur (int (/ number 10)) (conj result (mod number 10)))
result))]
(ddigits-helper number '())))
这种方法使用简单的数学来收集数字。它还显示了使用 recur
进行递归并使用累加器(result
参数)来收集中间结果。
这是我们假设现在对数字列表进行操作的两个初始函数:
(defn new-part [number size]
(take size number))
(defn rest-part [number size]
(drop size number))
如前所述,您还可以使用 partition
或 split-at
。
现在,您的主要功能可能如下所示:
(defn partition-number
[number size]
(let [digits (decimal-digits number)]
(cond (> size (count digits)) digits
true (cons (new-part digits size)
(partition-number
(digits-to-decimal (rest-part digits size))
size)))))
这在风格上与您的方法非常接近,但表明我们需要将数字转回数字,因为这正是 partition-number
所期望的。
(defn digits-to-decimal [digits]
(let [powers-of-ten (iterate (partial * 10) 1)
digits (reverse digits)]
(reduce +
(map-indexed (fn [position digit]
(* digit (nth powers-of-ten position)))
digits))))
但是,如果我们重组 partition-number
以也使用带累加器的辅助函数,我们也可以使用 recur
这就是避免在 clojure 中递归调用时炸毁堆栈的方法:
(defn partition-number
[number size]
(letfn [(partnumb-helper [digits size result]
(cond (> size (count digits)) (conj result digits)
true (recur (rest-part digits size)
size
(conj result (new-part digits size)))))]
(partnumb-helper (decimal-digits number) size '[])))
请注意,这种方式我们也一直在进行数字和数字之间的转换。
折叠哈希函数将其输入(在本例中为 int)分解为长度为 p 的片段并将这些部分相加。如果(not (= (mod input p) 0 ))
,即输入的长度不是p的倍数,最后一段可能是任意长度小于p。
到目前为止,这是我的代码:
(def firstX
(fn [x item]
(take x (str item))))
(def remX
(fn [x item]
(drop x (str item))))
(def divItemEq
(fn [a digits]
(cond (> digits (count (str a))) (a)
true (cons (list (firstX digits a)) (divItemEq (remX digits a) digits)))))
(def sumDigits
(fn [x]
(reduce + x)))
(def exItem1 76123451001214)
(print (sumDigits (divItemEq exItem1 3)))
目前无限递归(栈溢出)是因为divItemEq中的递归条件永远不满足。我试图解决这个问题导致了各种 type/casting 错误。
有什么改进的建议吗divItemEq
?
我不确定您不想使用哪些其他核心功能,但我想出了以下解决方案:
(defn chars->int [chars]
(Integer/parseInt (apply str chars)))
(defn int-partition [n count]
(loop [acc [] xs (str n)]
(if (seq xs)
(recur (conj acc (chars->int (take count xs))) (drop count xs))
acc)))
(int-partition 76123451001214 3)
;; yields
[761 234 510 12 14]
(reduce + (int-partition 76123451001214 3))
;; yields
1531
请注意,此版本并不懒惰,可能不适合大量输入。您可能希望使用 lazy-seq
.
这里有很多地方需要改进,首先是使用更惯用的 defn
而不是 (def name (fn
方案。接下来是你们的名字,我觉得不太清楚。其他人指出了您使用 partition
的方向,我同意,但在下面的解决方案中,我试图保持您方法的精神。
正如您自己发现的那样,将数字转换为数字序列很有意义,因为无论如何我们都需要序列操作。那么让我们从那个开始:
(defn decimal-digits [number]
(letfn [(ddigits-helper [number result]
(if (number > 0)
(recur (int (/ number 10)) (conj result (mod number 10)))
result))]
(ddigits-helper number '())))
这种方法使用简单的数学来收集数字。它还显示了使用 recur
进行递归并使用累加器(result
参数)来收集中间结果。
这是我们假设现在对数字列表进行操作的两个初始函数:
(defn new-part [number size]
(take size number))
(defn rest-part [number size]
(drop size number))
如前所述,您还可以使用 partition
或 split-at
。
现在,您的主要功能可能如下所示:
(defn partition-number
[number size]
(let [digits (decimal-digits number)]
(cond (> size (count digits)) digits
true (cons (new-part digits size)
(partition-number
(digits-to-decimal (rest-part digits size))
size)))))
这在风格上与您的方法非常接近,但表明我们需要将数字转回数字,因为这正是 partition-number
所期望的。
(defn digits-to-decimal [digits]
(let [powers-of-ten (iterate (partial * 10) 1)
digits (reverse digits)]
(reduce +
(map-indexed (fn [position digit]
(* digit (nth powers-of-ten position)))
digits))))
但是,如果我们重组 partition-number
以也使用带累加器的辅助函数,我们也可以使用 recur
这就是避免在 clojure 中递归调用时炸毁堆栈的方法:
(defn partition-number
[number size]
(letfn [(partnumb-helper [digits size result]
(cond (> size (count digits)) (conj result digits)
true (recur (rest-part digits size)
size
(conj result (new-part digits size)))))]
(partnumb-helper (decimal-digits number) size '[])))
请注意,这种方式我们也一直在进行数字和数字之间的转换。