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))

如前所述,您还可以使用 partitionsplit-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 '[])))

请注意,这种方式我们也一直在进行数字和数字之间的转换。