Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active November 13, 2020 02:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/fa4f9d8fd6ccd5929e84af222b402e7f to your computer and use it in GitHub Desktop.
Save ericnormand/fa4f9d8fd6ccd5929e84af222b402e7f to your computer and use it in GitHub Desktop.

Gapful numbers

Some numbers are gapful, some aren't. 100 is gapful because it has at least three digits and 100 is divisible by 10 ((str 1 0), the concatenation of the first and last digit). That's the definition of gapful: it has at least three digits and is divisible by the number formed by concatenating the first and last digits.

Create a function that takes a number and finds the closest gapful number. The function should return its argument if the argument itself is gapful. And if there are two gapful numbers equidistant to the argument, return the lower one.

Thanks to this site for the challenge idea!

(defn gapful? [n]
(let [divisor (Long/parseLong (str (first (str n)) (last (str n))))]
(and (> n 99) (zero? (mod n divisor)))))
(defn closest-gapful [n]
(if (gapful? n)
n
(if (< n 100)
100
(loop [lower (dec n)
upper (inc n)]
(if (or (gapful? lower) (and (gapful? lower) (gapful? upper)))
lower
(if (gapful? upper)
upper
(recur (dec lower) (inc upper))))))))
(defn gapful? [n]
(let [s (str n)]
(and (int? n)
(>= (count s) 3)
(let [d (Long/parseLong (str (first s) (last s)))]
(zero? (rem n d))))))
(defn closest-gapful [n]
(let [lowers (range (dec n) 99 -1)
highers (map #(+ % n) (range))
all (interleave highers lowers)]
(->> all
(filter gapful?)
first)))
(defn closest-gapful2 [n]
(loop [high? true low (dec n) high n]
(if high?
(if (gapful? high)
high
(recur false low (inc high)))
(if (gapful? low)
low
(recur true (dec low) high)))))
(ns scratches.gapful)
(comment
Challenge from https://purelyfunctional.tv/issues/purelyfunctional-tv-newsletter-361-tip-trampoline-your-tail-recursion/
Some numbers are gapful, some aren't. 100 is gapful because it has at least three digits and 100 is divisible by 10 ((str 1 0), the concatenation of the first and last digit). That's the definition of gapful: it has at least three digits and is divisible by the number formed by concatenating the first and last digits.
Create a function that takes a number and finds the closest gapful number. The function should return its argument if the argument itself is gapful. And if there are two gapful numbers equidistant to the argument, return the lower {one.})
(defn concat-fl
"concatates first and last digits of a number"
[n]
(let [nstr (seq (.toString n))]
(Integer/parseInt (str (first nstr) (last nstr)))))
(defn gapful?
"predicate to indicate if a number is 100 or more and divisible by it's first and last digits"
[n]
(let [fl-concat (concat-fl n)]
(if (and (>= n 100)
(= 0 (mod n fl-concat)))
true
false)))
;lazy sequence of gapful numbers
(def gapful-seq
(filter #(gapful? %) (range)))
(defn find-nearest-gapful
"Finds nearest gapful number. if equal distant, returns lowest number"[n]
(let [sm-gapful (last (take-while #(>= n %) gapful-seq))
lg-gapful (first (filter #(<= n % ) gapful-seq))]
(if sm-gapful (if (< (- lg-gapful n) (- n sm-gapful )) lg-gapful sm-gapful)
lg-gapful)))
(defn gapful [num]
(loop [candidates [num num]]
(let [gapful? (fn [n]
(when (and n (> n 99))
(let [d (as-> n v
(str v)
(str (first v) (last v))
(read-string v))]
(= (mod n d) 0))))
recruit (first (filter gapful? candidates))]
(if recruit
recruit
(recur [(dec (first candidates)) (inc (last candidates))])))))
(defn gapful? [n]
(when (> n 99)
(let [hi (loop [i n] (if (< i 10) i (recur (quot i 10))))
lo (rem n 10)
dd (+ lo (* 10 hi))]
(zero? (rem n dd)))))
(defn nearest-gapful
([n] (if (gapful? n) n (nearest-gapful n 1)))
([n dist]
(cond (gapful? (- n dist)) (- n dist)
(gapful? (+ n dist)) (+ n dist)
:else (recur n (inc dist)))))
(defn gapful? [n]
(let [s (str n)
divisor (Integer/parseInt (str (first s) (last s)))]
(zero? (mod n divisor))))
(defn closest [n]
(if (< n 100)
100
(first (filter gapful? (interleave (iterate inc n) (range (dec n) 99 -1))))))
@PEZ
Copy link

PEZ commented Jan 24, 2020

Yeah, I now see that I keep letting my gapful? function. That is debris from when I had misunderstood the problem and thought I wanted to close the divisor in... Here's my latest:

(defn closest-gapful [num]
  (if (< num 100)
    100
    (let [gapful? (fn [n]
                    (when (and n (> n 99))
                      (let [d (as-> n $
                                (str $)
                                (str (first $) (last $))
                                (read-string $))]
                        (= (mod n d) 0))))]
      (loop [candidates [num num]]
        (let [recruit (first (filter gapful? candidates))]
          (if recruit
            recruit
            (recur [(dec (first candidates)) (inc (last candidates))])))))))

I wonder a thing. When I try my closest-gapful using something like 1024M, the function never returns. I realise that my implementation isn't really prepared for that kind of input, but I don't understand why it would get stuck in infinity. Someone?

@miner
Copy link

miner commented Jan 27, 2020

Late to the party, but here's another implementation:

(defn gapful? [n]
  (when (> n 99)
    (let [hi (loop [i n] (if (< i 10) i (recur (quot i 10))))
          lo (rem n 10)
          dd (+ lo (* 10 hi))]
      (zero? (rem n dd)))))

(defn nearest-gapful
  ([n] (if (gapful? n) n (nearest-gapful n 1)))
  ([n dist]
   (cond (gapful? (- n dist)) (- n dist)
         (gapful? (+ n dist)) (+ n dist)
         :else (recur n (inc dist)))))

@zugnush
Copy link

zugnush commented Nov 13, 2020

(defn gapful?
  [n]
  (let [[h _ o] (str n)]
    (zero? (mod n (Integer. (str h o))))))

;; set up an infinte range of offsets -0 +0 -1 +1 -2 +2 ....
;; then find the first that is gapful
;; putting the minus first breaks ties in the right direction
;; the first means that the repeat at 0 is harmless
;; works from anywhere with any integer input

(defn closest-gapful
  [n]
  (->> (range)
       (map (juxt #(* -1 %) identity))  
       flatten
       (map #(+ n % ))
       (filter #(< 99 % 1000))
       (filter gapful?)
       first))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment