Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[haskell] number of numbers in a string

1,278 views
Skip to first unread message

ActiveX

unread,
Jun 28, 2004, 10:49:27 AM6/28/04
to
Hi all,

I am busy learning Haskell, but I ran into the following problem:
A sample string consist of the text "123abc456". Now I want to derive
the number of numbers in this string, which is 2 in this example
("123" and "456")
How can I program this is a simple manner, using the type definition
NumberOfDeci::String->Int?

Any help appreciated.

Kind Regards,

ActiveX

Adrian Hey

unread,
Jun 28, 2004, 9:53:20 PM6/28/04
to
ActiveX wrote:

I won't write the code for you, but I'll give you a few hints..
You can use isDigit to determine if a character is a decimal digit.
You can use dropWhile to delete leading leading digits or non-digits
as required.
If you start by deleting any leading non-digits, then either..
the resulting string is [], so NumberOfDeci=0
or..
the resulting string is not [] (begins with a digit), so NumberOfDeci
is one more than the NumberOfDeci you get after deleting the leading digits
from this string

Regards
--
Adrian Hey

Glynn Clements

unread,
Jun 29, 2004, 12:54:14 AM6/29/04
to

ma...@trance.nu (ActiveX) writes:

> I am busy learning Haskell, but I ran into the following problem:
> A sample string consist of the text "123abc456". Now I want to derive
> the number of numbers in this string, which is 2 in this example
> ("123" and "456")
> How can I program this is a simple manner, using the type definition
> NumberOfDeci::String->Int?

The following functions may prove useful:

Char.isDigit
List.group
and
filter
id
length
map

--
Glynn Clements <glynn.c...@virgin.net>

ActiveX

unread,
Jun 29, 2004, 3:27:04 PM6/29/04
to
Glynn Clements <glynn.c...@virgin.net> wrote in message news:<m37jtrd...@cerise.nosuchdomain.co.uk>...

Hi,

Thank you for your help.
I've now got the following which is ok until the +1:
NumberofDeci::String->Int
NumberofDeci string
| dropWhile isAlpha string=/[]=+1 AND dropWhile isDigit string
| dropWhile isAlpha string==[] = 0

How can I add 1 each time this is entered, and how can I let the
function proceed with dropWhili isDigit string?

Any help appreciated!!

Kind regards,
Marko

Glynn Clements

unread,
Jun 29, 2004, 7:29:04 PM6/29/04
to

ma...@trance.nu (ActiveX) writes:

> > > I am busy learning Haskell, but I ran into the following problem:
> > > A sample string consist of the text "123abc456". Now I want to derive
> > > the number of numbers in this string, which is 2 in this example
> > > ("123" and "456")
> > > How can I program this is a simple manner, using the type definition
> > > NumberOfDeci::String->Int?
> >
> > The following functions may prove useful:
> >
> > Char.isDigit
> > List.group
> > and
> > filter
> > id
> > length
> > map
>

> Thank you for your help.
> I've now got the following which is ok until the +1:
> NumberofDeci::String->Int
> NumberofDeci string
> | dropWhile isAlpha string=/[]=+1 AND dropWhile isDigit string
> | dropWhile isAlpha string==[] = 0
>
> How can I add 1 each time this is entered, and how can I let the
> function proceed with dropWhili isDigit string?

Let me put it another way. You can write the function you require
using nothing more than the functions which I listed previously, in
conjunction with the "." (composition) operator. You don't need to
write your own recursion.

Some more clues:

1. Start by feeding your string to "map isDigit". You only care
whether or not a character is a digit; any other distinctions are
irrelevant.

2. List.group does the "real work".

--
Glynn Clements <glynn.c...@virgin.net>

ActiveX

unread,
Jun 30, 2004, 4:51:24 AM6/30/04
to
Glynn Clements <glynn.c...@virgin.net> wrote in message news:<m3wu1qq...@cerise.nosuchdomain.co.uk>...

Ok, I really can't get out of it. Would you be so kind to give me the
answer, so I can reverse engineer the whole thing and learn something
from it.

thanks,
marko

Martin Ruderer

unread,
Jun 30, 2004, 4:56:49 AM6/30/04
to
On 30 Jun 2004 01:51:24 -0700
ma...@trance.nu (ActiveX) wrote:

> Ok, I really can't get out of it. Would you be so kind to give me the
> answer, so I can reverse engineer the whole thing and learn something
> from it.

I'm not him and very new to haskell, too. However, that's what I can
come up with:

count :: String -> Int
count s = length $ filter (any (== True)) $ group $ map isDigit s

Tomasz Zielonka

unread,
Jun 30, 2004, 5:13:01 AM6/30/04
to
Martin Ruderer wrote:
> I'm not him and very new to haskell, too. However, that's what I can
> come up with:
>
> count :: String -> Int
> count s = length $ filter (any (== True)) $ group $ map isDigit s

I can't resist making it shorter ;)

count s = length $ filter (any (== True)) $ group $ map isDigit s

count s = length $ filter (any id) $ group $ map isDigit s
count s = length $ filter and $ group $ map isDigit s
count = length . filter and . group . map isDigit

Best regards,
Tom

--
.signature: Too many levels of symbolic links

Ketil Malde

unread,
Jun 30, 2004, 5:23:47 AM6/30/04
to
Martin Ruderer <mar...@lddd.org> writes:

> I'm not him and very new to haskell, too. However, that's what I can
> come up with:

> count :: String -> Int
> count s = length $ filter (any (== True)) $ group $ map isDigit s

Since the cat is out of the bag, here are some small (arguably?)
improvements:

You don't need to name the parameter:

count = length . filter (any (== True)) . group . map isDigit

(== True) is the same as id on Bools:

count = length . filter (any id) . group . map isDigit

or you could perhaps just use a boolean operator like and or or (I
think which one you choose can affect efficiency, and depends on the
data):

count = length . filter or . group . map isDigit

For max efficiency, you only really need to look at the head, of
course. (We know that no empty strings will be returned, right?):

count = length . filter head . group . map isDigit

-kzm
--
If I haven't seen further, it is by standing in the footprints of giants

Adrian Hey

unread,
Jun 30, 2004, 6:16:24 AM6/30/04
to
I'm not sure the point free solution that's been suggested going to be much
help to a new bee. I think it's easier to understand recursion and use of
inductive reasoning first, even if Haskellers try to avoid using it :-)

So seeing as ActiveX has made an attempt with the solution I suggested (and
I can't be bothered with more hints:-) here's what I think is a simple
solution for a learner to grok ..

numberOfDeci :: String -> Int
numberOfDeci str = case dropWhile isNonDigit str of
[] -> 0
_:cs -> 1 + numberOfDeci (dropWhile isDigit cs)
where isNonDigit c = not (isDigit c)

Regards
--
Adrian Hey

Glynn Clements

unread,
Jun 30, 2004, 10:22:29 PM6/30/04
to

ma...@trance.nu (ActiveX) writes:

> Ok, I really can't get out of it. Would you be so kind to give me the
> answer, so I can reverse engineer the whole thing and learn something
> from it.

My solution was:

count = length . filter id . map and . group . map isDigit

[Essentially the same as Martin's/Tomasz' solutions, although slightly
more verbose.]

Let's break it down:

> map isDigit $ "123abc456"
[True,True,True,False,False,False,True,True,True]

> group . map isDigit $ "123abc456"
[[True,True,True],[False,False,False],[True,True,True]]

> map and . group . map isDigit $ "123abc456"
[True,False,True]

> filter id . map and . group . map isDigit $ "123abc456"
[True,True]

> length . filter id . map and . group . map isDigit $ "123abc456"
2

--
Glynn Clements <glynn.c...@virgin.net>

ActiveX

unread,
Jul 1, 2004, 6:28:10 AM7/1/04
to
Glynn Clements <glynn.c...@virgin.net> wrote in message news:<m3wu1ov...@cerise.nosuchdomain.co.uk>...

Thank you all for the reactions.
I'm now busy with Glynn's answer, since this is the easiest in my
opinion, although the solution with recursion is very helpfull as
well!
Now I want to determine the maximum length of the number of deci, so
"123abc1234" returns the maximum length, which is 1234.
I've tried to following:
maximum. length. filter id. map and. group. map isDigit

But I think the problem is that isDigit converts the real numbers into
a boolean value.
Am I on the good way with this solution?

Next I want to get the real maximum (highest number), which should be
a simplification of the above statement I have made:
maximum. filter id. map and. group. map isDigit
Is this right also?

Thank you all!

Kind regards,
Marko

Ketil Malde

unread,
Jul 1, 2004, 7:32:10 AM7/1/04
to
ma...@trance.nu (ActiveX) writes:

> Thank you all for the reactions.
> I'm now busy with Glynn's answer, since this is the easiest in my
> opinion, although the solution with recursion is very helpfull as
> well!
> Now I want to determine the maximum length of the number of deci, so
> "123abc1234" returns the maximum length, which is 1234.

Let's see how much we can recycle:

>> > map isDigit $ "123abc456"
>> [True,True,True,False,False,False,True,True,True]

Yep, the lengths are preserved.

>> > group . map isDigit $ "123abc456"
>> [[True,True,True],[False,False,False],[True,True,True]]

Yes, each list still has the correct length, and the ones containing
True correspond to numbers.

>> > map and . group . map isDigit $ "123abc456"
>> [True,False,True]

..but here we lost information we need.

> maximum. length. filter id. map and. group. map isDigit

> Am I on the good way with this solution?

Also you need to watch out, since you're working on lists of lists,
operations that you really want to apply to each element can
inadvertently be applied to the whole list instead.

Fire up Hugs or GHCi and toy around!

ActiveX

unread,
Jul 1, 2004, 2:57:07 PM7/1/04
to
Hi,

For problem#2, I've found the solution myself:

maxlengthDeci::String->Int
maxlengthDeci=maximum.map length. filter (any(==True)).group.map isDigit....

So far for this example!
But my following question: since isDigit converts all real numbers to
Booleans, how can I derive the maximum of NumberofDeci.
So input "123abc124" returns 124 since this is the largest number.

I've tried the following:
groupBy (\x y -> isDigit x&& isDigit y)
which converts "123abc124" into ["123", "a","b","c","124"]

Now I should filter for isDigits, so I get the following :(how??? tried map
isDigit.groupBy (\x y -> isDigit x&& isDigit y), but isn;t working):

["123","124"]

And the next problem is: maximum ["123","124"] returns "124" which is not an
integer.

So the problem can be split up in two parts:
-How can I Filter digits out of ["123", "a","b","c","124"]
-How van I Convert maximum ["123","124"] into maximum of type integer.

Please help me!

Solutions are welcome!

Thanks,

ActiveX

"Ketil Malde" <ke...@ii.uib.no> schreef in bericht
news:egfz8c0...@havengel.ii.uib.no...

Scott Turner

unread,
Jul 1, 2004, 4:15:04 PM7/1/04
to
ActiveX wrote:
> For problem#2, I've found the solution myself
Way to go!

> So the problem can be split up in two parts:
> -How can I Filter digits out of ["123", "a","b","c","124"]

What you want is not a direct property of the string, e.g. "123" or "b". You
need to look at one or more elements within the string.


> -How van I Convert maximum ["123","124"] into maximum of type integer.

'read' will convert a String to nearly any type you could wish.

ActiveX

unread,
Jul 1, 2004, 5:08:33 PM7/1/04
to
Hi,
I do not think that your solution is correct:

What you want is not a direct property of the string, e.g. "123" or "b". You
need to look at one or more elements within the string.

Because of the following:

[abc1abc12] will be converted by the code to:
["a","b","c","1","a","b","c","12"]

When I check for one element or more, the "1" will be filtered out as well,
together with a,b,c.

Any better solutions available??

Kind regards,
ActiveX

"Scott Turner" <ne...@pkturner.org> schreef in bericht
news:ydqdndVGx8l...@comcast.com...

Glynn Clements

unread,
Jul 1, 2004, 9:54:36 PM7/1/04
to
"ActiveX" <ma...@trance.nu> writes:


> But my following question: since isDigit converts all real numbers to
> Booleans, how can I derive the maximum of NumberofDeci.
> So input "123abc124" returns 124 since this is the largest number.
>
> I've tried the following:
> groupBy (\x y -> isDigit x&& isDigit y)
> which converts "123abc124" into ["123", "a","b","c","124"]
>
> Now I should filter for isDigits, so I get the following :(how??? tried map
> isDigit.groupBy (\x y -> isDigit x&& isDigit y), but isn;t working):

You probably want:

\x y -> isDigit x == isDigit y

I.e. True if either both are digits or neither are digits, False if
one is a digit and the other isn't.

> ["123","124"]
>
> And the next problem is: maximum ["123","124"] returns "124" which is not an
> integer.
>
> So the problem can be split up in two parts:
> -How can I Filter digits out of ["123", "a","b","c","124"]

"all" tests whether all elements of a list (strings are just lists of
characters) possess a given property, so "all isDigit" will return
True for a string composed entirely of digits and False otherwise.

> -How van I Convert maximum ["123","124"] into maximum of type integer.

"read".

--
Glynn Clements <glynn.c...@virgin.net>

Albert Lai

unread,
Jul 3, 2004, 12:18:39 PM7/3/04
to
Adrian Hey <ah...@NoSpicedHam.iee.org> writes:

> I'm not sure the point free solution that's been suggested going to be much
> help to a new bee. I think it's easier to understand recursion and use of
> inductive reasoning first, even if Haskellers try to avoid using it :-)

Both must be learned. Although in theory learning both at the same
time is overwhelming, I see in practice lots of students taking two
courses or more at the same time --- including one on recursion and
another on Unix shell scripting --- with no problem.

But what makes Unix shell scripting special anyway?

Sample Unix shell command:

grep '^X-Spam-Level' | sort | unique | wc -l

Sample Haskell function:

length . nub . sort . filter (isPrefixOf "X-Spam-Level")
(isPrefixOf and nub are from the List module)

<sarcasm>
Pointfree combinator programming is very intimidating, abstract, and
is no more than a theoretical curiosity --- you always put the points
back in real programs. Unix shell pipelining is very intuitive,
down-to-earth, and is a matter of bread-and-butter --- it is
impractical to create, track, and clean up temporary files in real
applications.
</sarcasm>

Bertrand Augereau

unread,
Jul 7, 2004, 3:50:22 PM7/7/04
to
Just an innocent question...
Is it an intellectual exercise to iteratively condense such a function to
make it shorter and shorter, or do you do such process when you develop real
world programs?
Seems to me it obfuscates the code and makes it harder to maintain, but
again, I'm not really fluent, and there might be really common FP idioms
that allow proficient readers to browse easily through condensed (more
"elegant" ;) ) forms.

"Ketil Malde" <ke...@ii.uib.no> a écrit dans le message de
news:eglli54...@havengel.ii.uib.no...

Scott Turner

unread,
Jul 7, 2004, 8:55:46 PM7/7/04
to
Bertrand Augereau a écrit:

> Is it an intellectual exercise to iteratively condense such a function to
> make it shorter and shorter, or do you do such process when you develop
> real world programs?
> Seems to me it obfuscates the code and makes it harder to maintain, but
> again, I'm not really fluent, and there might be really common FP idioms
> that allow proficient readers to browse easily through condensed (more
> "elegant" ;) ) forms.
Based on plenty of experience with functional and imperative programs, there
_is_ a similar process in real world programming. The main difference is
the metric that you apply. It still penalizes based on the count of
characters, but even more penalizes unfamiliar idioms, cryptic identifiers,
inconsistent indentation, etc.

It's still useful to study a function that has been condensed to a minimum
of characters, because it is likely to demonstrate techniques which are
effective but unusual.

Ketil Malde

unread,
Jul 8, 2004, 4:24:56 AM7/8/04
to
"Bertrand Augereau" <baug...@ifranke.com> writes:

> Is it an intellectual exercise to iteratively condense such a function to
> make it shorter and shorter, or do you do such process when you develop real
> world programs?

Both, to some extent.

>>> count :: String -> Int
>>> count s = length $ filter (any (== True)) $ group $ map isDigit s

>> You don't need to name the parameter:


>>
>> count = length . filter (any (== True)) . group . map isDigit

I generally do this.

>> (== True) is the same as id on Bools:
>>
>> count = length . filter (any id) . group . map isDigit

>> count = length . filter or . group . map isDigit

I would consider these intermediate steps, leading to

>> count = length . filter head . group . map isDigit

which I think is not so hard to understand: turn to booleans, group
them, filter out the ones whose head is True, and count the result.

Perhaps the 'filter head' could be replaced by
'filter (==True) . map head' if you feel that is clearer?

> Seems to me it obfuscates the code and makes it harder to maintain, but
> again, I'm not really fluent, and there might be really common FP idioms
> that allow proficient readers to browse easily through condensed (more
> "elegant" ;) ) forms.

You could say the same about using i++ instead of i=i+1 in C. It
isn't obfuscated when you're used to the idiom. Good naming and
conventions/idioms are important.

0 new messages