3

I want to calculate the sum of digits of a number in Scheme. It should work like this:

>(sum-of-digits 123)
 6

My idea is to transform the number 123 to string "123" and then transform it to a list '(1 2 3) and then use (apply + '(1 2 3)) to get 6.

but it's unfortunately not working like I imagined.

>(string->list(number->string 123))
'(#\1 #\2 #\3)

Apparently '(#\1 #\2 #\3) is not same as '(1 2 3)... because I'm using language racket under DrRacket, so I can not use the function like char->digit.

Can anyone help me fix this?

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
bearzk
  • 685
  • 3
  • 7
  • 22
  • ill have to look up that int -> string and string -> list stuff quick, but i can tell you for sure that `apply` isnt what you want in that last step. use `fold` (left or right doesnt matter here), or there might even be a native function `sum` – jon_darkstar Jun 15 '11 at 15:48
  • no, apply works fine. (apply + '(3 4)) produces 7. – John Clements Jun 15 '11 at 16:09
  • hmmm i guess so, i just tried the interpreter. i never really thought of apply that way but i see how it fits now. – jon_darkstar Jun 15 '11 at 16:13

6 Answers6

7

An alternative method would be to loop over the digits by using modulo. I'm not as used to scheme syntax, but thanks to @bearzk translating my Lisp here's a function that works for non-negative integers (and with a little work could encompass decimals and negative values):

(define (sum-of-digits x) 
  (if (= x 0) 0 
      (+ (modulo x 10) 
         (sum-of-digits (/ (- x (modulo x 10)) 10)))))
Stephen Rudolph
  • 1,385
  • 14
  • 20
  • 1
    thanks a lot!! I've changed your code according the scheme syntax `(define (sum-of-digits x) (if (= x 0) 0 (+ (modulo x 10) (sum-of-digits (/ (- x (modulo x 10)) 10)))))` – bearzk Jun 15 '11 at 16:23
  • `defun`? You just had to take the fun out of this, didn't you!? – BlackVegetable May 03 '14 at 16:02
3

Something like this can do your digits thing arithmetically rather than string style:

(define (digits n)
    (if (zero? n)
        '()
        (cons (remainder n 10) (digits2 (quotient n 10))))

Anyway, idk if its what you're doing but this question makes me think Project Euler. And if so, you're going to appreciate both of these functions in future problems.

Above is the hard part, this is the rest:

(foldr + (digits 12345) 0)

OR

(apply + (digits 1234))

EDIT - I got rid of intLength above, but in case you still want it.

(define (intLength x)
   (define (intLengthP x c)
      (if (zero? x)
          c
          (intLengthP (quotient x 10) (+ c 1))
      )
   )
   (intLengthP x 0))
jon_darkstar
  • 16,398
  • 7
  • 29
  • 37
  • right... prefix not infix =P thanks. as i was making that change you suggested the `zero?` predicate occurred to me. looks like im also being kind of overcautious with parens, gonna trim some out now – jon_darkstar Jun 15 '11 at 16:14
2

Those #\1, #\2 things are characters. I hate to RTFM you, but the Racket docs are really good here. If you highlight string->list in DrRacket and hit F1, you should get a browser window with a bunch of useful information.

So as not to keep you in the dark; I think I'd probably use the "string" function as the missing step in your solution:

(map string (list #\a #\b))

... produces

(list "a" "b")
John Clements
  • 16,895
  • 3
  • 37
  • 52
0

A better idea would be to actually find the digits and sum them. 34%10 gives 4 and 3%10 gives 3. Sum is 3+4.

Here's an algorithm in F# (I'm sorry, I don't know Scheme):

let rec sumOfDigits n =
    if n<10 then n
    else (n%10) + sumOfDigits (n/10)
Abdulsattar Mohammed
  • 10,154
  • 13
  • 52
  • 66
0

This works, it builds on your initial string->list solution, just does a conversion on the list of characters

(apply + (map (lambda (d) (- (char->integer d) (char->integer #\0)))
       (string->list (number->string 123))))

The conversion function could factored out to make it a little more clear:

(define (digit->integer d)
  (- (char->integer d) (char->integer #\0)))

(apply + (map digit->integer (string->list (number->string 123))))
John Gaines Jr.
  • 11,174
  • 1
  • 25
  • 25
-1
(define (sum-of-digits num)
    (if (< num 10)
        num
        (+ (remainder num 10) (sum-of-digits (/ (- num (remainder num 10)) 10)))))

recursive process.. terminates at n < 10 where sum-of-digits returns the input num itself.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92