0

A folding hash function breaks its input (int, in this case) to segments of p length and adds those parts. If (not (= (mod input p) 0 )), that is, the input's length is not a multiple of p, the last segment may be of an arbitrary length less than p.

Here's my code so far:

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

At the moment, infinite recursion (stack overflow) occurs because the recursive condition in divItemEq is never met. My attempts to fix this have resulted in various type/casting errors.

Any suggestions to how improve divItemEq?

David Shaked
  • 3,171
  • 3
  • 20
  • 31
  • You've explained the actual behavior (`StackOverflowError`); could you give the expected/desired behavior? – Sam Estep Mar 30 '16 at 02:26
  • Desired behavior: (divItemEq exItem1 3) evaluates to ((761) (234) (510) (012) (14)), which is passed to sumDigits. That application yields 1531. Sidenote: I corrected the recursive case upon second examination. I anticipate that my troubles stem from my elementary understanding of Clojure's type system. – David Shaked Mar 30 '16 at 03:24
  • 2
    Use [`partition`](https://clojuredocs.org/clojure.core/partition) instead. – jmargolisvt Mar 30 '16 at 03:27
  • I was looking to avoid built in functions, but thanks for the suggestion of `partition` @jmargolisvt – David Shaked Mar 30 '16 at 04:05
  • I suppose my trouble is converting the int input to something like a lat (list of atoms) – David Shaked Mar 30 '16 at 04:06
  • @DavidShaked If you're looking to avoid built-in functions, why are you using `take`, `str`, `drop`, `>`, `count`, `cons`, `list`, `reduce`, `+`, and `print`? – Sam Estep Mar 30 '16 at 12:52
  • @Elogent looking to avoid built-in function *to an arbitrary extent* – David Shaked Mar 30 '16 at 19:09

2 Answers2

2

There are quite some things to be improved here, the first would be to use the more idiomatic defn instead of (def name (fn scheme. The next would be your names which I find to be not very clear. Others have pointed you in the direction to use partition, which I would agree to, but in the solution below I tried to keep to the spirit of your approach.

As you've discovered yourself, it makes a lot of sense to turn the number into a sequence of digits, because we're gonna need sequence operations anyway. So let's start with that:

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

This approach uses simple math to collect the numbers. It also shows the use of recur for recursion and uses an accumulator (the result argument) to collect intermediate results.

Here are your two initial functions which we assume to operate on a list of digits now:

(defn new-part [number size]
  (take size number))

(defn rest-part [number size]
  (drop size number))

As discussed, you could also use partition or split-at.

Now, your main function could look like this:

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

This is very close in style to your approach but shows that we need to turn the digits back to a number because that's what partition-number expects.

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

However, if we restructure partition-number to also use a helper function with an accumulator, we can also use recur which is how one can avoid blowing the stack on recursive calls in 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 '[])))

Note that this way we also spare to convert between numbers and digits all the time.

schaueho
  • 3,419
  • 1
  • 21
  • 32
1

I am not sure what other core functions you don't want to use but I came up with the following solution:

(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

Note that this version is not lazy and may be inappropriate for large inputs. You might want to modify it using lazy-seq.

Piotrek Bzdyl
  • 12,965
  • 1
  • 31
  • 49