7
\$\begingroup\$

Let n be any integer between 1 and 999,999 inclusive. Your challenge is to write a complete program which using stdin or command-line arguments takes in n and outputs the number of times the letter "o" is needed to write all cardinal numbers in standard American English between 1 and n. You can assume that n will always be an integer within the above given range.

You can just use all lowercase letters as I do below. So we count all "o". No need to worry about uppercase "O".

Here is a quick review of how to write English numerals in American English.

one two three four ... nine ten eleven twelve thirteen fourteen ... nineteen twenty 
twenty-one twenty-two ... twenty-nine thirty ... forty ... fifty ... sixty ... 
seventy ... eighty ... ninety ... one hundred ... two hundred ... three hundred ... 
nine hundred ... one thousand ... two thousand ... nine thousand ... ten thousand ... 
eleven thousand ... ninety-nine thousand ... one hundred thousand ... 
two hundred thousand ... nine hundred ninety-nine thousand nine hundred ninety nine.

The hyphen for two digit numbers doesn't matter.

The commas don't matter of course. I excluded them above.

Separation between hundreds and tens doesn't matter because we are only counting the letter "o" so 110 can be written as "one hundred ten", or "one hundred and ten". I excluded the "and" above.

For this challenge "hundred" and "thousand" must be preceded by "one" instead of "a" when being used at the beginning of the number. So 1111 must be "one thousand one hundred eleven" instead of "a thousand one hundred eleven".

Here are some more random numerals to clarify.

219873 = two hundred nineteen thousand eight hundred seventy three
615023 = six hundred fifteen thousand twenty three
617610 = six hundred seventeen thousand six hundred ten
423716 = four hundred twenty-three thousand seven hundred sixteen
386031 = three hundred eighty-six thousand thirty one

Here are some samples for what your code should return.

./mycount 1
1

There's only "one" to write so we need only a single "o".

./mycount 10
3

We only need three o's namely in "one", "two", and "four".

./mycount 101
41

Your code must be self-contained and must not connect to the internet, download any files, perform any query, etc. I can already see somebody using google or mathematica with wolfram alpha to do this.

True code-golf. The shortest code in any language wins. Please post your code with some test cases. In the case of ties, I pick the one with the highest upvotes after waiting at least for two weeks. So everyone feel free to upvote any solutions you like.

Happy coding!

\$\endgroup\$
3
  • \$\begingroup\$ Related: Converting integers to English words \$\endgroup\$
    – primo
    Commented Dec 27, 2013 at 5:02
  • 6
    \$\begingroup\$ There are so many missing ands I just dropped my biscuit in my cuppa \$\endgroup\$
    – Bojangles
    Commented Dec 28, 2013 at 14:41
  • \$\begingroup\$ I think American numbers and numbers in English have the same amount of os - the only difference I know is the ands. \$\endgroup\$
    – bcsb1001
    Commented Mar 14, 2015 at 20:51

8 Answers 8

7
\$\begingroup\$

R - 54

sum(nchar(gsub("[^o]","",english::english(1:scan()))))

I get 41 for n=101. I hope someone can confirm.

\$\endgroup\$
4
  • 5
    \$\begingroup\$ This will not work if the package english has not been installed. To be fair, you should add the command necessary for installing the package. \$\endgroup\$ Commented Dec 27, 2013 at 10:38
  • 5
    \$\begingroup\$ I disagree. I have never seen such comment for python answers that contain import X or perl answers with use Y, etc. Having the necessary packages/modules installed is always a given. \$\endgroup\$
    – flodel
    Commented Dec 27, 2013 at 12:16
  • \$\begingroup\$ OK, now I see the point. \$\endgroup\$ Commented Dec 27, 2013 at 13:05
  • \$\begingroup\$ Yes, this works for me, too, although takes 2 seconds for 10000 and 25 seconds for 100000. For 999999, I got 2359000, which took 6 minutes. Nice! \$\endgroup\$ Commented Feb 28, 2016 at 11:18
3
\$\begingroup\$

JavaScript 1.8 (150)

function f(n)n<14?(22>>n)&1:n<100?((n/10|0)==4)+f(n%10):n<1e3?f(n/100|0)+f(n%100):f(n/1e3|0)+f(n%1e3)+1;m=readline();for(s=i=0;i++<m;)s+=f(i);print(s)

As written, this will only work in SpiderMonkey js (the one used by Anarchy Golf). If running this in Firefox, replace readline with prompt and print with alert. Use of Mozilla's nonstandard "expression closures" feature means this will not work in any other interpreter unless you insert {return and } in the necessary places (at a cost of 7 characters).

Original test cases:

  • 1 → 1
  • 10 → 3
  • 101 → 41

Some additional ones:

  • 1020 → 726
  • 21667 → 40173
  • 120000 → 262002
  • 999999 → 2359000
\$\endgroup\$
3
\$\begingroup\$

C - 147 148 157 163 166 172 200

C is the right tool for the job

s;l(x){s+=(22>>x%10&1)+(x/10%10==4)-!((x+89)/2%50);x&&l(x/100%10);}main(x,v)int**v;{for(x=atoi(v[1]);x;x--)l(x),l(x/1000),s+=x>999;printf("%d",s);}

Original tests:

  • 1 -> 1
  • 10 -> 3
  • 101 -> 41

Tests by @PleaseStand :

  • 1020 -> 726
  • 21667 -> 40173
  • 120000 -> 262602
  • 999999 -> 2359000

Plus some of my own random tests: http://qp.mniip.com/p/cy

\$\endgroup\$
2
\$\begingroup\$

Mathematica 49 58 50 bytes

Without a library or internet access.

StringCount[""<>IntegerName[Range@#,"Words"],"o"]&

Note:

"Words" guarantees that no digits will be left untranscribed into English.

This incorrectly returns one "o". (Emphasis added.)

IntegerName[1020]

1 thousand 20


This yields two "o"'s, as required. (Emphasis added.)

IntegerName[1020,"Words"]

one thousand, twenty


Example

StringCount[""<>IntegerName[Range@#,"Words"],"o"]&[1020]

726

\$\endgroup\$
2
\$\begingroup\$

Vyxal s, 6 bytes

ƛ∆ċ\oO

Try it Online!

Suggested by @emirps

Vyxal, 7 bytes

ɾ∆ċṅ\oO

Try it Online!

Num-to-words builtins FTW!

Explanation

ƛ∆ċ\oO  # Implicit input
ƛ       # Map over range:
 ∆ċ     #  Convert to words
   \oO  #  Count "o"
        # s flag sums the list
        # Implicit output

ɾ∆ċṅ\oO # Implicit input
ɾ       # One-range
 ∆ċ     # Convert to words
   ṅ    # Join into a string
    \oO # Count "o"
        # Implicit output
\$\endgroup\$
1
  • \$\begingroup\$ -1 byte using the s flag: Try it Online! \$\endgroup\$
    – emirps
    Commented Mar 28, 2023 at 18:43
1
\$\begingroup\$

Moo - 137 bytes

s=$string_utils;m=player;i=0;for a in[1..toint(read(m))]i=i+length(s:strip_all_but(s:english_number(a),"o"));suspend(0);endfor m:tell(i);

The suspend(0) is necessary to avoid a Task ran out of ticks for high inputs. Also, this code takes quite a long time to run for very high numbers.

\$\endgroup\$
1
\$\begingroup\$

Python + num2words, 81 bytes

lambda n:sum(num2words(i).count('o')for i in range(1,n+1))
from num2words import*
\$\endgroup\$
0
\$\begingroup\$

Perl - 384

#!/usr/bin/perl
@b=qw(1 1 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1);
sub b($){my($b,$m)=shift;if(20>$b){$b[$b];}elsif(100>$b){$m=$b%10;
$b[(($b-$m)/10)+18]+($m?b($m):0);}elsif(1000>$b){$m=$b%100;
b(($b-$m)/100)+($m?b($m):0);}elsif(1000000>$b){$m=$b%1000;
b(($b-$m)/1000)+1+($m?b($m):0);}}
sub c($){my$c=shift;my$d=0;$d+=b($c--)while($c);$d;}
print c($_)."\n"while(<>);

this would run faster with caching but that would increase my score

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.