Automate your first grade counting exercise

36

4

CodeGolf Challenge

PWSSHHHH! You wake up in a cryogenics lab in the year 3000. Upon being escorted to the assignment office to receive your career chip, presumably that of a delivery boy, a probe detects that you are from the year 2000. Because of this, and a few stereotypes, you are assumed stupid compared to today's modern human and are forced to repeat gradeschool.

You enter your first grade classroom and the teacher is giving an assignment. She will say or write a number up to 50. If she writes the number on the board (for example: 25) then you have to say the numbers up to that number "one, two, three, ..., twenty-five". If she says the number out loud (for example: "six") then, on your tablet, you have to write the numbers up to that number "1, 2, 3, 4, 5, 6"

This becomes very tedious and you decide you will automate the process with your still functioning, yet archaic, 21st century programming knowledge.


Objective:

Your program should take an input. This input will either be a decimal number (1 thru 50) or a written-out number (one thru fifty).

•If the input is a decimal number, your output should count from one to said number, using written-out style. (e.g. thirty-two)

•If the input is a written-out number, your output should count from 1 to said number, using decimal style. (e.g. 32)


Rules:

Input and Output can be in any case of your choosing (so you can make a program that only accepts upper-case if desired).

Input decimal numbers do not have to be of a number type (e.g. int), they can be a input string containing numbers (25 vs "25"). Either are fine and you can chose which one you want your program to accept. (Your program does not need to accept both)

Written out style does NOT require a hyphen between compound words, but you can if desired.

Output values have to be separated in some form, any separator is fine 1,2,3 1 2 3 etc

You can not add extra libraries like num2words (python) etc (However system libraries are fine)

Even though the back-story says you are from the year 2000, you can use languages created after that date (lol)


This is , so the program with the shortest bytecount wins!

Albert Renshaw

Posted 2017-01-31T09:18:23.483

Reputation: 2 955

1

Are we allowed to use libraries like num2words in case of python.

– Gurupad Mamadapur – 2017-01-31T09:56:06.687

@GurupadMamadapur thank you for asking, I am going to say no for the sake of this challenge, I think it takes too much fun out of it. Editing this into my post – Albert Renshaw – 2017-01-31T09:58:57.560

Just to be clear: "either" doesn't mean we have to choose the format we prefer, right? an answer should be able to handle both kinds of inputs (numbers and words). – coredump – 2017-01-31T13:24:27.027

Related: http://codegolf.stackexchange.com/q/57053/21348

– edc65 – 2017-01-31T13:27:43.207

1@AlbertRenshaw but what about builtins that do that? (Mathematica) – Pavel – 2017-01-31T18:06:56.293

1@coredump Either means you can pick one or the other or both. It doesn't have to be able to handle both kinds of inputs – Albert Renshaw – 2017-01-31T19:43:14.610

@AdmBorkBork system libraries are fine, edited into post. – Albert Renshaw – 2017-01-31T19:47:55.080

@Pavel those languages have an advantage I suppose, answers might be kind of boring though, I'm really enjoying seeing the creative solutions in languages that don't support that. This answer is great imo: http://codegolf.stackexchange.com/a/108776/16513

– Albert Renshaw – 2017-01-31T19:48:35.793

@AlbertRenshaw Ok thanks – coredump – 2017-01-31T20:44:45.950

2"Bite my shiny metal ass!" I won't count myself – RaisingAgent – 2017-02-01T13:22:17.750

1I keep thinking the title is "your first (grade counting)" not "your (first grade) counting" – CAD97 – 2017-02-03T14:36:56.440

Answers

32

Perl 6, 119 113 bytes

{my \n=<① ⑳ ㉑ ㉟ ㊱ ㊿>.map:{|map *.uniname.words[2..*].join,$^a..$^b}
/\d/??n[^$_]!!1..1+first $_,n,:k}

Unicode database FTW!

Uses upper-case written-out numbers without hypen, e.g. TWENTYTWO.
Returns a list of strings, or a range of numbers. (Both use space as separator when printed with put.)

smls

Posted 2017-01-31T09:18:23.483

Reputation: 4 352

3Very clever ahahaha! Love it – Albert Renshaw – 2017-01-31T19:44:33.010

13

Python3, 276 271 269 243 237 235 232 217 bytes

Taking a cue from the @smls perl submission...

from unicodedata import*
o=[name(chr(k)).split(' ',2)[-1]for j in['①⑴','㉑㉠','㊱㋀']for k in range(ord(j[0]),ord(j[1]))]
i=input()
w=i in o
for i in range(w and o.index(i)+1or int(i)):print(w and i+1or o[i])

I suspect it might be golfed a little bit further.

It makes use of the system library unicodedata to look up names for numbers. It requires upper case number names (separated by space: FORTY TWO) or decimal integers as input.

(This is my first code golf submission.)

(I also just noticed I was miscounting the length (encoding), so it's a few bytes less than previously thought. I've only updated the most recent byte count, though. Oops.)

unayok

Posted 2017-01-31T09:18:23.483

Reputation: 231

Welcome to PPCG! – AdmBorkBork – 2017-01-31T17:51:40.823

In advocacy: unicodedata is a system library that comes with the default installation, not an "extra" library that needs to be installed separately. – unayok – 2017-01-31T17:54:37.247

Welcome to the site! You can remove lots of spaces from your code.

– xnor – 2017-01-31T18:16:26.030

I can lose another dozen bytes if I don't bother with the join, but I end up with output like ['ONE', 'TWO', 'THREE']. While it technically fulfills the "any sort of separator" condition the prefix and suffix may be out of bounds. It doesn't quite feel like it adheres to the spirit of the challenge... – unayok – 2017-01-31T19:30:03.313

I am fine with a system library being used. I like this solution too – Albert Renshaw – 2017-01-31T19:47:16.483

1

Welcome to PPCG. You can lose 3 bytes by putting the print inside a for loop and having newlines between each output. print() doesn't care if it is an integer or a string then. Try it online!

– ElPedro – 2017-01-31T22:38:53.893

Thanks @ElPedro. I worked from your advice before looking at your link and came to basically the same result. – unayok – 2017-02-01T16:46:29.603

1I think you can import* instead of import name to save a couple of bytes – Post Rock Garf Hunter – 2017-02-02T17:54:58.753

10

Common Lisp, 297 253 243 242 144 128

(lambda(s)(#1=dotimes(u(or(#1#(i 51)(if(equal(#2=format()"~R"i)s)(return i)))s))(#2#t"~[~:;, ~]~:[~R~;~D~]"u(stringp s)(1+ u))))

Details

(lambda (s) 
  (dotimes                         ; iterate...                                                                          
      (u                           ; for u from zero below ...                
       (or                         ; if s is a string, then                   
        (dotimes (i 51)            ;   parse s by iterating from 0 to 50      
          (if (equal               ;   until we find a match between          
               (format nil "~R" i) ;   the English word(s) for i              
               s)                  ;   and the given s                        
              (return i)))         ;   (exit loop)                            
        s))                        ; otherwise, use s, which is a number      
    (format t                      ; for each U, print to standard output     
            "~[~:;, ~]~:[~R~;~D~]" ; (see below for details)                  
            u                      ; ...                                      
            (stringp s)            ; ... arguments to format                  
            (1+ u))))              ; ...                                      
  • ~[ 0 ~; 1 ~; ... ~:; else ~] is a switch, based on the next available argument's value, which jumps to the appropriate sub-control format. Here, I only have a case of "0" and for "else". This is used to insert a separator before each number except the first one, thanks to U starting from zero.

  • ~:[ FALSE ~; TRUE ~] is a conditional format; here we output things differently whether the input s is a string or not.

  • ~R write a number as a cardinal English number, whereas ~D simply prints the number.

Examples

CL-USER> (test "five")
1, 2, 3, 4, 5

CL-USER> (test 32)
one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty-one, twenty-two, twenty-three, twenty-four, twenty-five, twenty-six, twenty-seven, twenty-eight, twenty-nine, thirty, thirty-one, thirty-two

coredump

Posted 2017-01-31T09:18:23.483

Reputation: 6 292

From what I understand of the question, you have to be able to parse both styles, not just one, so your 55 byte solution might not be valid. "Your program does not need to accept both" is referring to 25 vs "25", the decimal as a number or as a string. – Tom – 2017-02-01T09:23:39.930

@TomDevs Thanks. This is definitely confusing. To be sure, if I define f so that "(f 2)" prints "one, two" and (f "two") prints "1, 2", does it look good to you? – coredump – 2017-02-01T09:30:53.633

Yep, I think that's right. – Tom – 2017-02-01T09:37:18.537

@TomDevs Thanks, I fixed it – coredump – 2017-02-01T10:09:25.897

I had a feeling Lisp would be used for this challenge! Does it support other languages too, just curious? – Albert Renshaw – 2017-02-14T23:46:20.003

1@AlbertRenshaw No, only English; this feature might be already considered as bloat, but since it was already implemented in some Lisps, it was standardized. – coredump – 2017-02-15T07:01:59.880

8

JavaScript ES6, 559 526 381 368 364 358 332 327 315 bytes

a="one0two0three0four0five0six0seven0eight0nine0ten0eleven0twelve0thir10four10fif10six10seven10eigh10nine1".replace(/1/g,'teen').split(0),b="twenty0thirty0forty0fifty".split(0),c=(n,d=Array,e=b.forEach(i=>a=a.concat(i,a.slice(0,9).map(x=>i+x))))=>1/n?a.slice(0,n).join():d.from(d(a.indexOf(n)+1),(x,i)=>i+1).join();

Thanks to Kritixi Lithos for the idea of splitting the array and Arnauld for the 1/n trick.

a="one0two0three0four0five0six0seven0eight0nine0ten0eleven0twelve0thir10four10fif10six10seven10eigh10nine1".replace(/1/g,'teen').split(0),b="twenty0thirty0forty0fifty".split(0),c=(n,d=Array,e=b.forEach(i=>a=a.concat(i,a.slice(0,9).map(x=>i+x))))=>1/n?a.slice(0,n).join():d.from(d(a.indexOf(n)+1),(x,i)=>i+1).join();

console.log(c("twentyfive"));
console.log(c("fifty"));
console.log(c(50));

Tom

Posted 2017-01-31T09:18:23.483

Reputation: 3 078

1You can remove the var and you can change the array ['one,'two',..] to "one0two0three0...".split(0) – user41805 – 2017-01-31T11:24:07.340

Redundant whitespace at null, Array(n). – Yytsi – 2017-01-31T11:40:46.253

2You can replace !isNaN(n) by 1/n. This gives you NaN for a string (falsy), a non-zero float for a non-zero integer (truthy), or Infinity for 0 (also truthy). – Arnauld – 2017-01-31T13:43:44.347

Add 4 spaces infront of every code line – sagiksp – 2017-01-31T14:06:50.370

@sagiksp Yeah, must have messed something up when editing the post, should be fixed now :) – Tom – 2017-01-31T14:15:54.820

6

PHP - 397 372 349 344 329 bytes

Inspired by TomDevs's JS solution

Saved 25 bytes by replacing $a=[...] by $a=explode(...)

Saved another 23 bytes by switching back to an array without string delimiters and by storing teen in a variable, thanks to @user59178

Saved another 5 bytes by removing the (int) typecasting

Saved another 15 bytes by dropping $b, the $i in the for declarations, and the curly braces, thanks to @user59178 again

$a=[one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir.$t=teen,four.$t,fif.$t,six.$t,seven.$t,eigh.$t,nine.$t];foreach([twenty,thirty,forty,fifty] as$c){$a[]=$c;for($i=0;$i<9;)$a[]=$c.'-'.$a[$i++];}if($argv[1]!=0)for($i=0;$i<$argv[1];)echo$a[$i++].' ';else for($i=1;$i<=array_search($argv[1],$a)+1;)echo$i++.' ';

Ungolfed :

$a =[one,two,three,four,five,six,seven,eight,nine,ten,eleven,‌​twelve,thir.$t=teen,‌​four.$t,fif.$t,six.$‌​t,seven.$t,eigh.$t,n‌​ine.$t];
foreach ([twenty,thirty,forty,fifty] as $c){
    $a[] = $c;
    for ($i=0;$i<9;)
        $a[] = $c . '-' . $a[$i++];
}
if( $argv[1] !=0 )
    for ($i=0;$i<$argv[1];)
        echo $a[$i++] . ' ';
else
    for ($i=1;$i<=array_search($argv[1], $a)+1;)
        echo $i++ . ' ';

Try it for an input string or for an input number

roberto06

Posted 2017-01-31T09:18:23.483

Reputation: 351

1When golfing you can use many strings directly without any quotes, including all the number you use. This causes a notice but that can be ignored. Additionally it's shorter (by 2 whole bytes) to store teen in a variable rather than repeating it each time. As such it would become: $a=[one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir.$t=teen,four.$t,fif.$t,six.$t,seven.$t,eigh.$t,nine.$t]; – user59178 – 2017-01-31T14:55:11.017

Hadn't thought of that, thanks ;) – roberto06 – 2017-01-31T15:19:42.660

You can save 7 more bytes by dropping $b and putting the second array directly into the foreach, 6 more bytes by dropping all the curly braces (though you need to put the $a=$c into the setup of the for loop) and 6 more bytes by post-incrementing $i when you use it rather than in the 'after' bit of the for loops. – user59178 – 2017-01-31T15:39:30.840

Save six bytes (two per loop) by moving the post-increment from the for to the following line: for ($i=0;$i<9;)$a[]=$c.'-'.$a[$i++]; – Alex Howansky – 2017-01-31T16:17:34.327

Ooops, sorry, just noticed that @user59178 suggested the same thing... – Alex Howansky – 2017-01-31T16:18:27.677

Wow, I didn't know I could omit the third parameter of a for, thanks ! – roberto06 – 2017-02-01T08:26:26.637

Well, you were still missing some golfing tricks and I was pretty sure I could beat the 315 byte javascript answer so here's a 306 byte modification: $a=[one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir.$t=teen,four.$t,fif.$t,six.$t,seven.$t,eigh.$t,nine.$t];foreach([twenty,thirty,forty,fifty]as$c)for($a[]=$c;$i<9;)$a[]=$c.'-'.$a[$i++?:0];if(0<$t=$argv[1])for(;$j<$t;)echo$a[$j++?:0].' ';else for(;$j++<=array_flip($a)[$t];)echo$j.' '; The main savings were from assigning $argv[1] to a 1 byte variable and switching to using un-initialised loop counters. – user59178 – 2017-02-01T12:48:38.397

Well, it seems like removing the $a[] = $c; declaration causes bugs : https://eval.in/728469 (for a string input) and https://eval.in/728468 (for an int input).

– roberto06 – 2017-02-01T13:48:32.207

You're right, I didn't test properly. Sorry. for($a[]=$c,$i=0;$i<9;)$a[]=$c.'-'.$a[$i++]; works. – user59178 – 2017-02-01T14:48:32.190

6

Scheme, 161, 152, 149

(define (c x)(let((r(string->number x)))(let l((i 1))(let((n (format #f "~r" i)))(display(if r n i))(newline)(or(eq? r i)(equal? x n)(l (+ i 1)))))))

Uncompressed:

(define (count limit)
  (let ((numerical-limit (string->number limit)))
    (let l ((i 1))
      (let ((current-number (format #f "~r" i)))
        (display (if numerical-limit current-number i))
        (newline)
        (or (eq? numerical-limit i)
            (equal? limit current-number)
            (l (+ i 1)))))))

Michael Vehrs

Posted 2017-01-31T09:18:23.483

Reputation: 771

How do you convert from e.g. "four" to 4? I am not sure string->number does this, I checked quickly and it seems to be used to convert e.g. from string "4" to number 4. – coredump – 2017-01-31T12:20:03.120

@coredump That is correct. (string->number "four") returns #f. – Michael Vehrs – 2017-01-31T12:58:41.483

Which Scheme are you running? – coredump – 2017-01-31T19:12:13.943

1@coredump guile 2.0.9 – Michael Vehrs – 2017-02-01T06:25:04.733

6

Python 2, 503 499 494 490 479 bytes

-5 with thanks to @JonathanAllan

l='one two three four five six seven eight nine ten eleven twelve thir#four#fif#six#seven#eigh#nine#'.replace('#','teen ').split()
m='twenty','thirty','forty','fifty'
i,z,R=raw_input(),' ',range
try:n=int(i);p=(n/10)-2;o=(l+sum([[m[x]]+[m[x]+z+l[y]for y in R(9)]for x in R(p)],[])+[m[p]]+[m[p]+z+l[y]for y in R(n%10)],l[:n])[n<20]
except:j=i.split();o=map(str,R(1,(m.index(j[0])+2)*10+l.index(j[1])+2if z in i else l.index(i)+2if i in l else(m.index(i)+2)*10+1))
print','.join(o)

Try it online!

Input either a number or a space seperated spelling of a number.

Slightly less golfed and more readable version:

l='one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen'.split()
m='twenty','thirty','forty','fifty'
i=raw_input()
try:
 n=int(i)
 if n<20:
  o=l[0:n]
 else:
  o=l
  for x in range((n/10)-2):
   o+=[m[x]]+[m[x]+' '+l[y]for y in' '*9]
  p=m[(n/10)-2]
  o+=[p]+[p+' '+l[y]for y in' '*n%10]
except:
 if' 'in i:
  t=i.split()
  s=((m.index(t[0])+2)*10)+l.index(t[1])+2
 else:
  s=l.index(i)+2 if i in l else((m.index(i)+2)*10)+1
 r=range(1,s)
 o=map(str,r)
print','.join(o)

ElPedro

Posted 2017-01-31T09:18:23.483

Reputation: 5 301

16 byte save with l="one two three four five six seven eight nine ten eleven twelve thir#four#fif#six#seven#eigh#nin#".replace("#","teen ").split() – Jonathan Allan – 2017-01-31T15:40:44.330

...oops 5, missed the e from nineteen. – Jonathan Allan – 2017-01-31T15:47:38.793

Is there a reason you need to use Python 2, without it the print would be longer, but the raw_input could just be input? (Same question for your other answer) – nedla2004 – 2017-02-01T00:30:12.060

@nedla2004 - No reason other than that I haven't got round to installing Python 3 on my latest laptop yet :-) – ElPedro – 2017-02-01T08:10:11.603

6

Python 2, 262 bytes

x="one two three four five six seven eight nine ten eleven twelve thir#four#fif#six#seven#eigh#nine#".replace("#","teen ").split()
x+=[a+"ty"+b for a in"twen","thir","for","fif"for b in['']+x[:9]]
v=input()
for s in range(1,x.index(v)+2)if v>50else x[:v]:print s

repl.it

Input and output strings are lower case and concatenated*, so to test a string input enter, for example, "thirtyfive" at the prompt.

Builds the list of all the words (plus "fiftyone" to "fiftynine"), x, then tests if input is a word with the proxy v>50 (strings are greater than numbers in Python 2, and all the numbers in the valid input range from the specification are <=50) and prints the appropriate values by either slicing the list, x[:v], or building a range of integers, range(1,x.index(v)+2).

* Adding hyphenation on both costs 11 bytes, by replacing a+"ty"b with a+"ty"+'-'*(b>'')+b.

Jonathan Allan

Posted 2017-01-31T09:18:23.483

Reputation: 67 804

5

JavaScript (ES6), 261 bytes

Note: the string assigned to z is encoded with atob. In the encoded string there are 11 bytes that I can not post to this site, even if they are valid characters in a javascript string. So I used an hex escape in the form \xHH. Each one of these escapes is counted as 1 byte.
The original uncompressed string is the less golfed version.

x=>(z=btoa('ö\x89ÞöÜ(öØkyï_¢êý~+Þöȱöǯz\x7f^\x8a\x08möx§{Û^\x9f×¥z÷§öÜ\x1e\x96÷½¶\x18«÷×â\x7fß}z(!÷Ûpz\x7f}~\x8aý').split(9),o=(0+z.map((v,i)=>i<20?i<13?v:(v||z[i-10])+'teen':z.slice(0,10).map(d=>(z[i]||z[i-8]||z[i-18])+'ty'+d))).split`,`,p=o.indexOf(x),o.slice(1,-~x+p+!~p).map((x,i)=>~p?i+1:x))

Less golfed

x => (
  z = '9one9two9three9four9five9six9seven9eight9nine9ten9eleven9twelve9thir99fif999eigh99twen99for9'
      .split(9),
  o = (0 + // 0 + array to build a comma separated string
       z.map( (v, i) => 
         i < 20 
         ? i < 13 
           ? v // 1 to 13 are 'as is'
           : (v||z[i-10])+'teen' // compose for 14 to 19
         : z.slice(0,10).map(d=>(v||z[i-8]||z[i-18])+'ty'+d)) // 20s, 30s, 40s, 50s
      ).split`,`, // from comma separated to array again
  // o contains strings from one to fiftynine
  p = o.indexOf(x), // look for input
  o.slice(1, -~x+p+!~p).map((x,i) => ~p?i+1:x)
)

Test

F=
x=>(z=btoa('ö\x89ÞöÜ(öØkyï_¢êý~+Þöȱöǯz\x7f^\x8a\x08möx§{Û^\x9f×¥z÷§öÜ\x1e\x96÷½¶\x18«÷×â\x7fß}z(!÷Ûpz\x7f}~\x8aý').split(9),o=(0+z.map((v,i)=>i<20?i<13?v:(v||z[i-10])+'teen':z.slice(0,10).map(d=>(v||z[i-8]||z[i-18])+'ty'+d))).split`,`,p=o.indexOf(x),o.slice(1,-~x+p+!~p).map((x,i)=>~p?i+1:x))

function update() {
  var i=I.value
  O.textContent = F(i)
}  

update()
<input id=I value=25 oninput='update()'><pre id=O></pre>

edc65

Posted 2017-01-31T09:18:23.483

Reputation: 31 086

ö\x89ÞöÜ(öØ... this stuff is great hahaa – Albert Renshaw – 2017-01-31T22:01:19.140

5

Python 2, 432 422 416 403 bytes

I'm sure this can be improved on. At the very least if I can get away with hardcoding the value to be worked on and not needing a function I can save 20. It needs a space to separate words in text input. Saved 6 bytes thanks to JonathanAllan's comment on ElPedro's answer, 4 for rearranging maths.

def z(f):
 a,b,i,d="one two three four five six seven eight nine ten eleven twelve thir#four#fif#six#seven#eigh#nine#".replace("#","teen ").split()+[""],"twenty thirty forty fifty".split(),1,f>50
 if d:f=f.split();f=a.index(f[-1])+21+b.index(f[-2])*10 if len(f)>1 else b.index(f[-1])*10+20 if f[-1]in b else a.index(f[-1])+1
 while i<=f:s=i if d else a[i-1]if i<20 else b[i//10-2]+a[i%10-1];print s;i+=1

(NB: The actual version of this uses tabs to indent instead of spaces. QPaysTaxes added a single space because that wasn't rendering properly, to ensure that the given code compiles. It shouldn't change the byte count.)

Chris H

Posted 2017-01-31T09:18:23.483

Reputation: 581

@JonathanAllan's comment on ElPedro's answer works here too for -6 – Chris H – 2017-01-31T16:02:43.927

1len(`f`)>2 can be ...`f`[2:] for another 3 I believe. (ignore the ... can't seem to get the backticks working properly) – Jonathan Allan – 2017-01-31T16:13:14.950

In fact in python 2 you could go for f>50 for 6. (and another one by not using d) – Jonathan Allan – 2017-01-31T16:17:29.657

@JonathanAllan that doesn't work for passing numbers as integers, which I currently do: TypeError: 'int' object has no attribute '__getitem__'. If I pass numeric input as a string, f[2:] gets closer but still fails when trated as a boolean (print f[2:] and True prints a blank line if len(f)<2, not True or False) – Chris H – 2017-01-31T16:25:19.743

@JonathanAllan f>50 works, thank you. Dropping d isn't so simple as I always put the end value of the loop into f so line 8 can't be changed to if f>50 as it will never be true. – Chris H – 2017-01-31T16:29:44.197

With the backticks it makes sense – Chris H – 2017-01-31T16:33:13.733

Off by one error for words less then "twenty" (a.index(f[-1])+1). – Jonathan Allan – 2017-01-31T17:23:29.597

Upvoted but then noticed that for input of 22 it gives nineteen twentynineteen twentyone as the output. Try it online!. I won't remove the upvote until you have had time to fix it.

– ElPedro – 2017-01-31T18:50:25.143

@ElPedro that's bizarre, as it doesn't do that for 25, though I have seen that bug and it comes back quite easily so it might be a pasting error. I can't test on my phone but I would guess that I end up with a[-1] and the solution is to add +[""] to the definition of a for +5 bytes. – Chris H – 2017-02-01T06:49:00.953

@ElPedro the fix was as I thought, plus another bugfix. Saved a few by nesting ternaries – Chris H – 2017-02-01T09:08:22.220

@JonathanAllan I think I introduced that one when trying to get a shorter defintion of d working. Your fix implemented, thanks. Byte count is still down because I could combine some lines – Chris H – 2017-02-01T09:10:25.890

@Chris - Looks good! – ElPedro – 2017-02-01T09:10:37.903

@ElPedro and another -3, which I realised as I wrote the previous comment to you. – Chris H – 2017-02-01T09:12:53.100

Is it just me or would this cause a syntax error because the contents of z aren't indented? – Fund Monica's Lawsuit – 2017-02-02T01:52:26.800

@QPaysTaxes if those lines aren't indented it's a formatting error when I uploaded the latest version and doesn't affect the byte count. They're indented by tabs in my source, which I can't fix on mobile. If the indent was 4 spaces the reason would be obvious, so I'm not sure what happened. I'll fix it later – Chris H – 2017-02-02T06:57:05.733

Ah, alright. That makes sense. With your permission, I'll edit it to use a single space in front of the last three lines. – Fund Monica's Lawsuit – 2017-02-02T06:59:03.120

@QPaysTaxes thank you, that would be kind. – Chris H – 2017-02-02T07:34:13.413

@ChrisH I didn't get your reply until just now. Edit suggested. – Fund Monica's Lawsuit – 2017-02-02T08:32:35.173

5

Python 3, 305 303 bytes

Converted to Python 3 after advice from @nedla2004. Now also has no space between written numbers on input or output e.g. enter twentytwo

l='one two three four five six seven eight nine ten eleven twelve thir#four#fif#six#seven#eigh#nine#'.replace('#','teen ').split()
m='twenty','thirty','forty','fifty'
i,R=input(),range
l+=sum([[m[x]]+[m[x]+l[y]for y in R(9)]for x in R(3)],[])
for x in R(1,l.index(i)+2)if i in l else l[:int(i)]:print(x)

Try it online 3!

Python 2, 327 320 313 308 bytes

l='one two three four five six seven eight nine ten eleven twelve thir#four#fif#six#seven#eigh#nine#'.replace('#','teen ').split()
m='twenty','thirty','forty'
i,R=raw_input(),range
l+=sum([[m[x]]+[m[x]+l[y]for y in R(9)]for x in R(3)],[])+['fifty']
for x in R(1,l.index(i)+2)if i in l else l[:int(i)]:print x

Try it online 2!

163 170 177 bytes shorter than my original answer so I am posting it as an alternative. This uses for on the two lists to build up a complete list of all of the string representations of the numbers then identifies the right one in the list and prints everything up to it either by value or by index. Outputs a new line for each value.

ElPedro

Posted 2017-01-31T09:18:23.483

Reputation: 5 301

5

Wolfram Language, 92 bytes

If[NumberQ@#, Do[Print@IntegerName@i, {i, #}], 
  Do[Print@i, {i, Interpreter["SemanticNumber"]@#}]] &

(I'm new to this, let me know if I did something wrong)

user6014

Posted 2017-01-31T09:18:23.483

Reputation: 288

2-10 bytes: Do[Print@If[#>0,i,,IntegerName@i],{i,If[#>0,#,,Interpreter["SemanticNumber"]@#]}]& – JungHwan Min – 2017-02-01T02:01:33.023

4

C++11, 484 480 477 bytes

#import<iostream>
#import<cstdlib>
#import<vector>
using namespace std;f(){int j,i=2;string s="teen";vector<string>v={"","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"};for(;i++<9;)v.push_back(v[i]+s);v[13]="thir"+s;v[15]="fif"+s;v[18]="eigh"+s;for(i=19;i++<50;){string n[4]={"twenty","thirty","forty","fifty"};v.push_back(n[i/10-2]+v[i%10]);}cin>>s;if(i=atoi(s.c_str()))for(j=0;j++<i;)cout<<v[j]<<" ";else while(v[i++]!=s)cout<<i<<" ";}

Text input in lower-case without hyphens.

Steadybox

Posted 2017-01-31T09:18:23.483

Reputation: 15 798

3

PowerShell, 362 bytes

$z=0..50|%{("0twenty0thirty0forty0fifty"-split0)[+(($b="$_"[0])-gt49)*($_-gt19)*(+"$b"-1)]+($x=(("0one0two0three0four0five0six0seven0eight0nine0ten0eleven0twelve"-split0)+(-split'thir four fif six seven eigh nine'|%{$_+'teen'})))[($_%10)*($_-gt19)]+$x[$_*($_-le19)]}
if(($n=-split$args)[0][0]-in48..57){$z[$n[0]..$n[2]]}else{$z.IndexOf($n[0])..$z.IndexOf($n[2])}

Try it online! words input or numbers input

This is a right mess, and I'm not terribly happy with it, but here it is. Golfing suggestions welcome.

The first line sets $z to be an array of the full English words. You can see the -split0 for numbers 1 to 12, and the loop to construct all the teens, and then there's a bunch of logic to put everything together right. Try it online!

The second line starts with some logic. We take the input $args (as a string), -split it on whitespace, store it into $n for use later, take the first [0] word, and the first [0] character of that, and check if it is -in a range 48..57 (i.e., ASCII 0 to 9). So, we're checking if we have decimal input or English input. Try it online!

In the first case, we build a range based on the decimal inputs $n[0]..$n[2] and use that to index into $z[...]. In the other case, we find the .indexOf() the first word and the last word, and build just a numerical range from that. In either situation, we now have an array of objects on the pipeline (either strings or integers), and an implicit Write-Output at program completion gives us a newline between elements.

AdmBorkBork

Posted 2017-01-31T09:18:23.483

Reputation: 41 581

3

Swift3, 402 bytes

let f=["one","two","three","four","five","six","seven","eight","nine"]
let g=["twenty","thirty","forty","fifty"]
let v=[f,["ten","eleven","twelve"],["thir","four","fif","six","seven","eigh","nine"].map{$0+"teen"},[g[0]],f.map{g[0]+$0},[g[1]],f.map{g[1]+$0},[g[2]],f.map{g[2]+$0},[g[3]]].flatMap{$0}
func c(s:String){if let i=Int(s){print(v.prefix(upTo:i))}else{for j in 1...v.index(of:s)!+1{print(j)}}}

Ungolfed:

let f = ["one","two","three","four","five","six","seven","eight","nine"]
let g = ["twenty","thirty","forty","fifty"]

let values = [f,["ten","eleven","twelve"],["thir","four","fif","six","seven","eigh","nine"].map{$0+"teen"},
              [g[0]], f.map{g[0]+$0},
              [g[1]], f.map{g[1]+$0},
              [g[2]], f.map{g[2]+$0},
              [g[3]]].flatMap{$0}

func count(s:String){
    if let i = Int(s) {
        print(values.prefix(upTo: i))
    } else {
        for j in 1...values.index(of: s)!+1{
            print(j)
        }
    }
}

count(s:"29")
count(s:"twentyeight")

Nothing special here, just using an array to back up the written-out numbers.

I originally thought this solution using this other way to calculate the values array:

let values = f + ["eleven","twelve"]
    + ["thir","four","fif","six","seven","eigh","nine"].map{$0+"teen"}
    + [g[0]] + f.map{g[0]+$0}
    + [g[1]] + f.map{g[1]+$0}
    + [g[2]] + f.map{g[2]+$0}
    + [g[3]]

Which could be golfed to:

let v=f+["eleven","twelve"]+["thir","four","fif","six","seven","eigh","nine"].map{$0+"teen"}+[g[0]]+f.map{g[0]+$0}+[g[1]]+f.map{g[1]+$0}+[g[2]]+.map{g[2]+$0}+[g[3]]

replacing the 3rd line in the golfed code

I could have scored 381 bytes, but, there is a compiler error that says: "expression was too complex to be solved in reasonable time", more info on the error can be found here

Rodrigo Ruiz Murguía

Posted 2017-01-31T09:18:23.483

Reputation: 81

LOVE seeing swift in here, I'll have to check this out more when I get back – Albert Renshaw – 2017-02-01T01:00:49.540

3

R, 452 430 424 bytes

o=c("","one","two","three","four","five","six","seven","eight","nine") 
t=gsub(0,"teen",c("ten","eleven","twelve","thir0","four0","fif0","six0","seven0","eigh0","nine0"))
s=c("twenty","thirty","forty") 
p=""
for(i in s){for(j in o){p=paste0(p,i,j," ")}}
as.data.frame(t(d<-1:50))
names(d)=c(o[-1],t,as.vector(strsplit(p," ")[[1]]),"fifty")
f=function(x){if(is.numeric(x)){names(d)[1:x]}else{matrix(d[1:d[x]],dimnames=NULL)}}

#> f(5)
#[1] "one"   "two"   "three" "four"  "five" 

#> f('five')
#     [,1]
#[1,]    1
#[2,]    2
#[3,]    3
#[4,]    4
#[5,]    5

Places the numbers in a data.frame with written-out numbers as column names, making the translation between the two (and subsequent printing) pretty easy.

Main attempt at golfing was in creating the written-out numbers for 20-49, probably much more to golf here.

I made an attempt with as.matrix to print the data.frame with just the numbers, but am still left with a matrix header. Hopefully that's ok.

Ungolfed:

ones <- c("","one","two","three","four","five","six","seven","eight","nine") 
teens <- c("ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen")
tens <- c("twenty","thirty","forty") 

p=""
for(i in tens){
  for(j in ones){
    p=paste0(p, i, j," ")
  }
}

nums <- 1:50
as.data.frame(t(nums))
names(nums) <- c(ones[-1], teens, as.vector(strsplit(p, " ")[[1]]), "fifty")
f <- function(x){
  if(is.numeric(x)){
    names(nums)[1:x]
  } else {
    matrix(nums[1:nums[x]], dimnames = NULL)
  }
}

BLT

Posted 2017-01-31T09:18:23.483

Reputation: 931

Slight improvement to 359 Bytes: o=c("","one","two","three","four","five","six","seven","eight","nine") ; v=c("ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"); w=c("twenty","thirty","forty"); a=data.frame(0:50, c(o,v, sapply(w[1:3],function(y) sapply(o,function(x) paste0(y,x))),"fifty")); b=which(a==i); a[if(b<52) 2:b else 2:(b-51),ifelse(b<52,2,1)] – count – 2017-02-01T15:02:08.760

@count looks like a big improvement! I can't seem to figure out where the function is, though, or where you'd take an argument. – BLT – 2017-02-01T15:49:08.527

2

C, 342 331 bytes

char*x[]={"teen","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thir","four","fif","twenty","thirty","fourty","fifty"};void main(int z,char**i){for(z=1;z<=atoi(i[3]);z++)printf("%s%s%s\n",z<16?x[z]:z<20?z^18?x[z-10]:"eigh":x[z/10+14],z>20&&z%10?"-":z>12&&z<20?*x:"",z>20&&z%10?x[z%10]:"");}

Try it online!

Ahemone

Posted 2017-01-31T09:18:23.483

Reputation: 608

My favorite language :) – Albert Renshaw – 2017-02-04T09:36:46.617

1You actually don't need the 1 thru or one thru; all this codegolf requires is your third argument. The first two will always be "1 and thru" (or "one and thru") – Albert Renshaw – 2017-02-04T09:38:44.517

@AlbertRenshaw Good call! Thanks :) – Ahemone – 2017-02-04T11:05:57.543

1

SAS, 179

%macro c(n);%let f=words.;%if%length(&n)>2%then%do;%do c=1%to 50;%if%qsysfunc(putn(&c,&f))=&n%then%let n=&c;%end;%let f=2.;%end;%do i=1%to &n;%put%sysfunc(putn(&i,&f));%end;%mend;

Output is written to the log separated by newlines. SAS has a built-in format for converting digits to words, which is a major advantage for this challenge, but annoyingly it lacks an informat for doing the reverse.

user3490

Posted 2017-01-31T09:18:23.483

Reputation: 809