Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Created October 19, 2021 14:24
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/642261cb154219ec6c1fb01c6cab33f9 to your computer and use it in GitHub Desktop.
Save ericnormand/642261cb154219ec6c1fb01c6cab33f9 to your computer and use it in GitHub Desktop.
447 PurelyFunctional.tv Newsletter

Product of digits of sum

Write a function that takes one or more numbers as arguments. It should sum them, then multiply the digits. If the answer is one digit long, it's done. If it's more than one digit, repeat and multiply the digits again.

Examples

(sum-prod 4) ;=> 4
(sum-prod 10) ;=> 0 (since the sum is two digits, then 1 * 0)
(sum-prod 11 12) ;=> 6
(sum-prod 12 16 223) ;=> 0 (work it out!)

Thanks to this site for the problem idea, where it is rated Very Hard in Java. The problem has been modified.

Please submit your solutions as comments on this gist.

To subscribe: https://purelyfunctional.tv/newsletter/

@jonasseglare
Copy link

(defn sum-prod [& values]
  (->> values
       (apply +)
       (iterate (fn [x] (transduce (map #(- (int %) 48)) * (str x))))
       rest
       (drop-while #(not (zero? (quot % 10))))
       first))

@jaihindhreddy
Copy link

(defn- digit-prod
  "returns the product of the digits of a non-negative int"
  [n]
  (if (zero? n) 0
    (loop [prod 1 n n]
      (if (zero? n) prod
        (recur (* prod (rem n 10))
               (quot n 10))))))

(defn sum-prod
  ([x]
    (->> (iterate digit-prod x)
         (drop-while #(> % 9))
         first))
  ([x & xs]
    (sum-prod (reduce + x xs))))

@mchampine
Copy link

mchampine commented Oct 19, 2021

(defn sum-prod [& ns]
  (let [digits #(->> % str (map (comp read-string str)))
        sp (apply * (digits (apply + ns)))]
    (if (= 1 (count (digits sp)))
      sp
      (sum-prod sp))))

@souenzzo
Copy link

souenzzo commented Oct 19, 2021

(letfn [(number->digits [base n]
          (let [next-n (quot n base)]
            (conj (if (zero? next-n)
                    []
                    (number->digits base next-n))
              (mod n base))))
        ; Write a function that takes one or more numbers as arguments
        (sum-prod [& vs]
          (let [; It should sum them
                sum (apply + vs)]
            (loop [digits (number->digits 10 sum)]
              (let [;; then multiply the digits
                    prod (apply * digits)
                    digits (number->digits 10 prod)]
                (case (count digits)
                  ; If the answer is one digit long, it's done
                  1 prod
                  ; If it's more than one digit, repeat and multiply the digits again
                  (recur digits))))))]
  (sum-prod 4)
  (sum-prod 10)
  (sum-prod 11 12)
  (sum-prod 12 16 223))

@nbardiuk
Copy link

nbardiuk commented Oct 19, 2021

(defn- sum [xs]
  (reduce + 0 xs))

(defn- product [xs]
  (reduce * 1 xs))

(defn- fixed-point [f x]
  (->> (iterate f x)
       (partition 2 1)
       (drop-while #(apply not= %))
       ffirst))

(defn- digits [x]
  (for [c (str x)]
    (- (int c) (int \0))))

(defn sum-prod [x & xs]
  (->> (sum (cons x xs))
       (fixed-point (comp product digits))))

@KingCode
Copy link

KingCode commented Oct 19, 2021

EDIT: I added handling of negative sums, based on the assumption that when the sum is negative,
one of the digits's value is negative when multiplying and therefore each product thereafter also.

(defn digits [x]
  (->> x str (sequence (comp (map int) (map #(- % (int \0)))))))

(defn sum-prod [x & xs]
  (let [sum (->> xs (cons x) (apply +))
        sign (if (neg? sum) - identity)]
    (->> (if (neg? sum) (- sum) sum)
         (iterate (fn [xs]
                    (->> xs digits (apply *))))
         (drop-while #(< 9 %))
         first
         sign)))
(sum-prod 12 16 223) ;=> 0 (work it out!)
(sum-prod -1 2 3 4 5 60) ;=> 2 
(sum-prod -80 2 30) ;=> -6

@mmeroberts
Copy link

mmeroberts commented Oct 19, 2021

 ;; Version 1 

(defn digits 
 "I did look this one up"
[n]
  (->> n str 
       (map (comp read-string str))))                                                  
 
(defn sum-prod [& args]
    (loop [d (reduce * (digits (reduce + args)))]
        (if (> d 9)
          (recur (reduce * (digits d)))
          d)))

;; Version 2

(defn prod[x]
  (if (< x 9)
    x
    #(prod(reduce * (digits x)))))
  
(defn sum-prod [& args]
  (trampoline prod (reduce + args)))

@KubqoA
Copy link

KubqoA commented Oct 20, 2021

(defn sum-prod [& numbers]
 (let [sum (apply + numbers)
       digits (map #(- (int %) (int \0)) (str sum))
       prod (apply * digits)]
  (if (> prod 9) (recur [prod]) prod)))

@stuartstein777
Copy link

(defn mult-digits-until-single-digit [xs]
  (let [res (->> xs
                 str
                 (map (comp str identity))
                 (map #(Integer/parseInt %))
                 (reduce *))]
    (if (< res 10)
      res
      (mult-digits-until-single-digit res))))

(defn sum-prod [& args]
  (->> args
       (apply +)
       mult-digits-until-single-digit))

@jonasseglare
Copy link

C++ template metaprogramming implementation:

template <int N>
struct DigitProduct {
  static const int value = (N % 10)*(DigitProduct<N / 10>::value);
};

template <>
struct DigitProduct<0> {
  static const int value = 1;
};

template <int N, bool stop>
struct DigitProductLoop {
  static const int next = DigitProduct<N>::value;
  static const int value = DigitProductLoop<next, next < 10>::value;
};

template <int N>
struct DigitProductLoop<N, true> {
  static const int value = N;
};

template <int ... X>
struct Sum {};

template <int a, int ... X>
struct Sum<a, X ...> {
  static const int value = a + Sum<X...>::value;
};

template <>
struct Sum<> {
  static const int value = 0;
};

template <int N>
class Display;

int main() {
  Display<DigitProductLoop<Sum<12, 16, 223>::value, false>::value> display;
}

will display the result in the form of an error message from the compiler:

error: aggregate ‘Display<0> display’ has incomplete type and cannot be defined

@miner
Copy link

miner commented Oct 22, 2021

(defn sum-prod
  ([n & nums] (sum-prod (reduce + n nums)))
  ([^long n]
   (if (< n 10)
     n
     (recur (long (loop [prod 1 n n]
                    (if (zero? n)
                      prod
                      (recur (* prod (rem n 10)) (quot n 10)))))))))

Note: the type hints improve performance

@JonathanHarford
Copy link

(defn sum-prod [& numbers]
  (loop [sum (apply + numbers)]
    (if (< sum 10)
      sum
      (recur (->> sum str (map #(Integer/parseInt (str %))) (apply *))))))

@dfuenzalida
Copy link

dfuenzalida commented Oct 23, 2021

Better late than never. The tricky part is that if the product is larger than 10 you multiply the digits again until you get a 1-digit number.

(defn reduce-digits [x]
  (->> x str (map (comp read-string str)) (reduce *)))

(defn sum-prod [& xs]
  (->> xs (reduce +) reduce-digits
       (iterate reduce-digits)
       (drop-while #(>= % 10))
       first))

;; (sum-prod 4) ;=> 4
;; (sum-prod 10) ;=> 0
;; (sum-prod 11 12) ;=> 6
;; (sum-prod 12 16 223) ;=> 0

@led
Copy link

led commented Oct 27, 2021

(defn sum-prod [& n]
  (loop [n (reduce + n)
         r (if (zero? n) 0 1)]
    (if (zero? n)
      (if (< r 10) r (sum-prod r))
      (recur (quot n 10) (* r (mod n 10))))))

;; (sum-prod 0) -> 0
;; (sum-prod 4) -> 4
;; (sum-prod 11 12) -> 6
;; (sum-prod 12 16 223) -> 0
;; (sum-prod 1 2 3 4 5 6) -> 2
;; (apply sum-prod (range 10000))   -> 0

@dhoboy
Copy link

dhoboy commented Nov 10, 2021

(defn sum-prod
  [n & args]
  (let [sum (+ n (apply + args))]
    (reduce
      #(str (* (Integer/parseInt %1) (Integer/parseInt %2)))
      (map #(str %) (str sum)))))

;; testing
(sum-prod 4) ;; 4
(sum-prod 10) ;; 0
(sum-prod 11 12) ;; 6
(sum-prod 12 16 233) ;; 12 

how do you get colors in github comments?

@stuartstein777
Copy link

@dhoboy

put clojure after your first ` tags

@jumarko
Copy link

jumarko commented Jan 26, 2022

https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/purely_functional/puzzles/0447_longest_alternating_substring.clj#L1

(defn- multiply-digits [number]
  (apply * (mapv (comp parse-long str) (str number))))

(defn sum-prod
  "Takes one or more numbers as arguments.
  Sum them, then multiply the digits.
  If the answer is one digit long, it’s done.
  If it’s more than one digit, repeat and multiply the digits again."
  [& numbers]
  (let [sum (apply + numbers)]
    (loop [num sum]
      (let [product (multiply-digits num)]
        (if (< 9 product)
          (recur product)
          product)))))

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