lispracket

Racket: how to get the number of occurrences of a character in a string


I'm trying to get de number of occurrences of a character in a string, in RACKET.

I´m passing the Character "#\a" and I shoud receive an 3.

What I'm doing wrong?

(define (numCaracter character string1)
  (numCaracter-aux character string1 0 0))

(define (numCaracter-aux c s1 numC x)
   (cond
     ((= x (string-length s1)) numC)
     ((eq? c (string-ref s1 x)) (numCaracter-aux c s1 (+ 1 numC) (+ 1 x)))
     (else (numCaracter-aux c s1 numC (+ 1 x))))) 

(numCaracter "#\a" "banana")

Solution

  • There are two problems with your code:

    The second of these is a subtle and important point. What eq? does is tell you if two objects are in fact the same identical object. But there can be objects which you would call 'the same' which are in fact not the same object. A good example of this is numbers: it might seem obvious that (eq? 1 1) should be true. But what about

    (define (big n m)
      (for/product ([e (in-range 1 n)])
        (* e m)))
    
    (eq? (big 100 123) (big 100 123))
    

    (big 100 123) is 742351665480632681361574507959522940219863107926668019564998091421702580066558131502770412261037347873964172894230830459668242628528330665058838091519120194482100362028630508871608854457172959508668790743797878802883944000708882685320114585932837885833026170012541369814338006896897825563613579482679096651236246935631886366444007162831175680000000000000000000000. This is a number far too big for the machine to represent: it has about 1200 bits. Each time this number is created some large structure is created in memory, and in general these structures will be different objects. So eq? returns #f when comparing two such numbers, or it almost certainly does so.

    But I'd like to treat them as the same thing, and (as well as specialized predicates for numbers), there is a predicate which returns true if two immutable objects are semantically the same. That predicate is eqv?.

    It may not be obvious that the same is true for characters, but it is. The reason for this is that characters are not tiny objects in general: they can be fully-fledged Unicode things which can be quite big. So, again, eqv? does the right thing for characters.

    However, you might want to just use a predicate whose purpose is to compare characters, which will not only work, but will catch your other mistake for you.

    Finally: you could modify your code to go backwards through the string: why would this make it simpler?