counting characters in strings

Started by cormullion, June 04, 2006, 01:12:18 AM

Previous topic - Next topic

cormullion

I wonder if there's a better way to count the number of occurrences of a character in a string, rather than convert both to lists first:


(count (list "a") (explode a)

Nothing wrong with it other than it being a bit roundabout! ;-)

m i c h a e l

#1
Quote from: "cormullion"
I wonder if there's a better way to count the number of occurrences of a character in a string, rather than convert both to lists first:


I'll playfully assume you did not mean this:


> (set 'a (dup "abcdefg" 5))
"abcdefgabcdefgabcdefgabcdefgabcdefg"
> (define (num-chars s) (count (args) (explode s)))
(lambda (s) (count (args) (explode s)))
> (num-chars a "b" "g" "a" "x")
(5 5 5 0)
> _


But something more like this:


> _


Imagine the prompt blinking away, patiently waiting.



"Where is michael?", the prompt quietly thinks to itself after some time passes.


> _


After a while, the prompt blurts out, "Here he is! Must have been off in the manual, seeing how to do it."


> _


"Now he's pressing the . . . Control key? Control key. Why would he . . . Not D! Not Control-[click]"


> ^D
bash> _


Every way I tried to finagle it, lists ended up crashing the party. I suspect something like the string buffer functions would be the tool of choice, but I'll leave the answer up to one of the club's newrus (newLISP gurus ;-)



m i c h a e l

cormullion

#2
Quote from: "m i c h a e l"
Quote from: "cormullion"
I wonder if there's a better way to count the number of occurrences of a character in a string, rather than convert both to lists first:


I'll playfully assume you did not mean this:


> (set 'a (dup "abcdefg" 5))
"abcdefgabcdefgabcdefgabcdefgabcdefg"
> (define (num-chars s) (count (args) (explode s)))
(lambda (s) (count (args) (explode s)))
> (num-chars a "b" "g" "a" "x")
(5 5 5 0)
> _



Correct. Converting the strings to lists is indeed the 'roundabout'-ness of which I spoke.


Quote from: "m i c h a e l"
But something more like this:


> _


Imagine the prompt blinking away, patiently waiting.



"Where is michael?", the prompt quietly thinks to itself after some time passes.


> _


After a while, the prompt blurts out, "Here he is! Must have been off in the manual, seeing how to do it."


> _


"Now he's pressing the . . . Control key? Control key. Why would he . . . Not D! Not Control-[click]"


> ^D
bash> _


Every way I tried to finagle it, lists ended up crashing the party. I suspect something like the string buffer functions would be the tool of choice, but I'll leave the answer up to one of the club's newrus (newLISP gurus ;-)



m i c h a e l


Um, yes. What substances have you been ingesting today? ;-)

Lutz

#3
Cormullion's function is the best method of counting characters in a string:



(define (num-chars s)
    (count (args) (explode s)))


but just as an interesting exercise I wrote this function counting characters in a string without breaking it up:



(define (num-chars str)
    (let (result)
        (dolist (c (args))
            (replace c str "")
            (push $0 result -1))
        result))

> (num-chars a  "b" "g" "a" "x")
(5 5 5 0)
>


it uses the fact that replace puts the count of replacemenets into the system variable $0.



Lutz

cormullion

#4
Yes, LUtz, that's a good idea!



My initial question was inspired in part by the fact that I couldn't remember whether 'count' was one of the set of functions that doesn't work for both lists and strings. It's a very pleasant aspect of newLISP that you can often use the same function for both lists and strings, and I had to look carefully in the manual before I realised that 'count' was strictly list-only.



It's no problem!

cormullion

#5
I think it was m i c h a e l ' s function. I may have mis-double-re-un-counter-quoted him....

Lutz

#6
Quote
It's a very pleasant aspect of newLISP that you can often use the same function for both lists and strings, and I had to look carefully in the manual before I realised that 'count' was strictly list-only.


... and slowly I am trying to round out the API and make list-only functions work on strings too. The last addition to work on strings was 'push/pop'; 'count', 'rotate' and 'member' are the next and I probably will stop there. For some functions it just doesn't make much sense, like the set functions 'intersect', 'difference' and 'unique' which will always only work on lists or functions working on associations like 'assoc' and 'replace-assoc'.



'count' could also be able to count whole substrings, not only characters and perhaps accept regular expressions ... we will see.



Lutz