Alphabetize Integers

19

2

Alphabetize Integers

For a given set of numbers, put them in alphabetical order when they are spelled out (i.e. 1: one, 2: two, 90: ninety, 19: nineteen). Your code should work for the range [-999999, 999999]. Output must have a delimiter between numbers. A space will work, as will a space and a comma as shown in the examples below. Input can be an array of integers, a string of delimited numbers, or however you see fit. All integers are assumed to be unique.

Numbers are not hyphenated for the purposes of this challenge and spaces are alphabetized before any other characters. Negative numbers are assumed to be expressed by using the word minus. For example, four would precede four thousand and the number -40 would be sorted using the string minus forty. Assume all numbers will be solely comprised of number words and no conjunctions (e.g. use two thousand forty two instead of two thousand and forty two).


Test Cases

Single Digit Integers:

Input:

1, 2, 3, 4, 5

Output:

5, 4, 1, 3, 2

Multiple Digit Integers:

Input:

-1002, 5, 435012, 4, 23, 81, 82

Output:

81, 82, 5, 4, 435012, -1002, 23

Spaces between words, no hyphens, commas or "and":

Input:

6, 16, 60, 64, 600, 6000, 60000, 60004, 60008, 60204, 60804

Output:

6, 600, 6000, 16, 60, 64, 60000, 60008, 60804, 60004, 60204

Remember, this is , so the code with the fewest bytes wins. No loopholes allowed!

wubs

Posted 2016-12-01T20:20:47.513

Reputation: 363

Here is the link to the relevant sandbox post.

– wubs – 2016-12-01T20:23:05.473

Will the input ever contain more than one of a single integer? – ETHproductions – 2016-12-01T20:42:28.387

@ETHproductions No, it will not. I'll specify that in the question. – wubs – 2016-12-01T20:43:54.773

8Welcome to PPCG. Nice avatar. :D Nice first question. – AdmBorkBork – 2016-12-01T20:50:06.857

@TimmyD Thanks! I'm looking forward to PowerShell-ing everything I can around here. – wubs – 2016-12-01T21:05:50.700

Will the input ever contain a zero? – ETHproductions – 2016-12-02T02:36:31.577

@ETHproductions Yes. All numbers for the range [-999999,999999]. – wubs – 2016-12-02T14:40:14.293

I was reading the Wayside School series to my kids and A Wonderful Teacher (the second chapter 19 in Wayside School is Falling Down) inspired me to write a challenge to output the names of all the numbers zero to one million in alphabetical order. I'd say this already covers that challenge with only a few tweaks. I wonder if Miss Zarves would accept the output as an answer...

– Engineer Toast – 2017-05-30T15:02:42.470

Answers

5

JavaScript (ES6), 189 179 186 bytes

let f =

a=>a.sort((x,y)=>!x-!y||(X=q(x),Y=q(y),X>Y)-(X<Y),q=n=>n<0?"L"+q(-n):n>999?q(n/1e3)+"Z"+q(n%1e3):n>99?q(n/100)+"K"+q(n%100):n>19?"  cYHFVSCO"[n/10|0]+q(n%10):"0PdaIGTQAMWDbXJEURBN"[n|0])

let g = a => console.log(`[${f(a)}]`)

g([1,2,3,4,5])
g([-1002,5,435012,4,23,81,82])
g([0,1000,1100])
<input id=I value="1 2 3 4 5"><button onclick="g(I.value.match(/\d+/g)||[])">Run</button>

The basic idea is to convert each input number into a short string that's in the correct lexographical position compared to all other number-string pairs. Here's the dictionary used: (Don't run the snippet; it's just used to hide the long list.)

A eight
B eighteen
C eighty
D eleven
E fifteen
F fifty
G five
H forty
I four
J fourteen
K hundred
L minus
M nine
N nineteen
O ninety
P one
Q seven
R seventeen
S seventy
T six
U sixteen
V sixty
W ten
X thirteen
Y thirty
Z thousand
a three
b twelve
c twenty
d two

This creates a very concise way of mapping each number to its lexographically correct position. That's what the recursive q function does:

q(-X)        => "L" + q(X)
q(XYYY)      => q(X) + "Z" + q(YYY)
q(XYY)       => q(X) + "K" + q(YY)
q(XY >= 20)` => "  cYHFVSCO"[X] + q(Y)
q(X)         => "0PdaIGTQAMWDbXJEURBN"[X]

The 0 at the beginning of the string is to ensure that e.g. 100 (one hundred, converted to PK0) is sorted before 101 (one hundred one, converted to PKP). This creates an odd scenario where 0 (zero) is sorted to the front of the array, so to get around this, in the sorting function we first sort any zeroes to the right with !x-!y||(....

ETHproductions

Posted 2016-12-01T20:20:47.513

Reputation: 47 880

Looks like it doesn't work for [1100, 1000]. I would expect the output to be 1000 (one thousand), 1100 (one thousand one hundred), but the output is the same order as input. – milk – 2016-12-01T21:38:03.383

@milk Hmm... I'm not sure why this happens, but I'll look into it. – ETHproductions – 2016-12-01T22:18:37.707

@milk Ah, 1000 is being parsed as one thousand zero; I'll fix this momentarily. Must we support 0 on its own though? It's a unique case that will add 15 bytes or so to my code. – ETHproductions – 2016-12-01T22:22:29.107

11

Inform 7, 214 201 118 bytes

Inform 7 is an absolutely terrible language for golfing, so I wanted to give it a chance here.

Indentation should use tab (\t) characters, but HTML doesn't like those. Conversely, Inform doesn't like spaces for indentation, so you'll have to replace the spaces with tabs if you copy-paste the code from here to test it. Or just copy-paste from the Markdown source instead.

Golfed:

To X:
    repeat through Table 1:
        now Q entry is "[R entry in words]";
    sort Table 1 in Q order;
    say "[R in Table 1]".

Input should be an Inform table, like so (with \t between the columns):

Table 1
R (number)  Q (text)
-1002
5
435012
4
23
81
82

Output:

81, 82, 5, 4, 435012, -1002, 23

This function runs through the table once, adding a textual representation of each number in a new column. Then it sorts the table rows according to the text column; in Inform, strings are sorted lexicographically. Finally, it prints out the original column in the new order. Conveniently, Inform 7's "crude but sometimes useful" format for printing out table columns turns out to be comma separated, exactly as requested.

Ungolfed, with boilerplate showing how to call the function:

To print the numbers in alphabetical order:
    repeat through the Table of Sortable Numbers:
        now the name entry is "[the index entry in words]";
    sort the Table of Sortable Numbers in name order;
    say "[the index column in the Table of Sortable Numbers]".

Table of Sortable Numbers
index (number)  name (text)
-1002
5
435012
4
23
81
82

There is a room.
When play begins: print the numbers in alphabetical order.

Draconis

Posted 2016-12-01T20:20:47.513

Reputation: 561

1I'm slightly confused by this. Is words a reference of the spelled out versions of numbers, built into Inform 7? – Pavel – 2016-12-01T20:52:40.120

1@Pavel Indeed! "(number) in words" returns a string with a textual representation of the number. It conveniently uses "minus" for negative numbers, and while it puts hyphens between words, it does so consistently and alphabetizes hyphens before all letters (so the end result is the same). – Draconis – 2016-12-01T20:57:48.123

2+1 for the language choice. I'd have to check, but I suspect there are some golfing opportunities left, though; for example, does the parser really require all those "the" articles? And you'd have to ask the OP, but I don't see any obvious reason why " and " would not be a valid delimiter. Even if not, a single space is explicitly allowed, so just say "[R entry] " should suffice. – Ilmari Karonen – 2016-12-01T23:01:01.690

I'd say the "and" at the end is fine. I didn't say that the delimiters had to be uniform, so this is a perfectly acceptable answer. If I could give points for most interesting answer, I would give it to you. I really enjoy the readability of this language, even golfed. Nice job! – wubs – 2016-12-02T18:56:11.530

I finally got a chance to play with Inform7 a bit, and managed to re-golf your entry down to just 118 bytes. Since posting Inform code in comments doesn't work very well, I went ahead and edited it into your answer directly. I hope you don't mind, feel free to revert and/or tweak my edits any way you like if you do. – Ilmari Karonen – 2016-12-10T19:25:07.083

...and, unfortunately, I found a bug in the sorting: it turns out that hyphens do matter, e.g. for the comparison between 44 ("forty four") and 40004 ("forty thousand four"). This can be fixed with a string replacement like replace the text "-" in Q entry with " ", but that costs a lot of bytes. Also, it turns out that, to correctly sort the test case 40, 44, 40000, 40804, 40004 (which should sort in that order), you'll also need Use American dialect (to get rid of "and") and replace the text "," in Q entry with "" (to remove a comma from 40804. :( – Ilmari Karonen – 2016-12-10T19:56:59.763

4

Mathematica, 67 bytes

SortBy[#,#~IntegerName~"Words"~StringReplace~{","->"","-"->""}&]&

Unnamed function taking a list of integers as its argument and returning a list of integers as its value. #~IntegerName~"Words" is a built-in that changes an integer to its name in English. IntegerName sometimes has commas and hyphens in its output, so the StringReplace call gets rid of those. (Sadly the hyphen is actually the 3-byte character, 8208, in UTF-8.) Then SortBy sorts the original list alphabetically according to the value of the modified integer name.

A nice coincidence: IntegerName uses negative instead of minus in its output—but no word appearing in the names of any of the allowed numbers is alphabetically between those two words, so no replacement is needed!

(Hat tip to ngenisis for reminding me of Sortby.)

Greg Martin

Posted 2016-12-01T20:20:47.513

Reputation: 13 940

Kudos! I came very close to getting this solution, but that dash was giving me headaches! – ngenisis – 2016-12-01T22:12:30.927

Does your answer here actually use the correct hyphen? If I copy what you have here into Mathematica it doesn't replace the hyphens from IntegerName. The Wolfram documentation says that it is unicode character 2010.

– ngenisis – 2016-12-01T22:38:32.747

Probably not, then—I tried to get the correct hyphen in this answer, but looks like I didn't succeed. – Greg Martin – 2016-12-02T02:11:21.453

I cut your answer in half ;) – J. Antonio Perez – 2016-12-02T15:27:41.643

And then some... you make unnecessary modifications to the string. – J. Antonio Perez – 2016-12-02T15:28:12.760

4

Bash + GNU utils + bsdgames, 52

  • 4 bytes saved thanks to @izabera.
sed 's/.*/echo `echo &|number`:&/e'|sort|sed s/.*://

I/O is newline-delimited lines.

  • The first sed expression replaces each numerical number with a shell command that outputs the word form of the number (as given by the bsdgames number utility), followed by a : then the numerical form of the number.
  • This is then sorted.
  • Then the second sed strips leading characters up to and including the :, leaving the numerical form sorted as required.

number correctly handles "minus", and its output is close enough to the specificed format that the sort works as required. It does output "fourty-four" instead of "fourty four", but this shouldn't matter from the sorting perspective.

The bsdgames package may need installation:

sudo apt-get install bsdgames

The sed and sort utilities are almost certainly already in your distro.

Digital Trauma

Posted 2016-12-01T20:20:47.513

Reputation: 64 644

-t: is useless and you can use number<<<& – izabera – 2016-12-02T02:06:33.683

@izabera Yes - thanks - I removed the -t:. However, sed's eval feature runs commands using sh, so bash features like <<< won't work. – Digital Trauma – 2016-12-02T17:38:22.257

it works fine as long as your sh is bash :P – izabera – 2016-12-02T22:49:41.907

@izabera Nope - if bash as started as sh it tries to emulate Posix sh as much as possible, which means that bashisms such as <<< are turned off. GNU sed's eval feature starts commands with /bin/sh -c ... and not /bin/bash -c .... Have you tried this? – Digital Trauma – 2016-12-02T23:32:58.867

bash never turns off <<<, not even in posix mode – izabera – 2016-12-03T00:13:39.927

@izabera Sorry - I was mistaken. I thought /bin/sh was symlinked to /bin/bash on my Ubuntu 16.04 VM, but its not - it is symlinked to /bin/dash. Conversely on my macOS machine it is /bin/bash and you're right - <<< does work in in sh. But this answer won't work on macOS because of the dependency on bsdgames number which I don't want to jump through the hoops of to install on macOS. I'm sure there are other Linux distros out there that will allow the <<< version of this answer, but I'm sticking with Ubuntu for now. – Digital Trauma – 2016-12-03T02:02:48.603

This answer appears to be locale-dependent: in the en_US.UTF-8 locale this correctly sorts 44 before 40004 for me (on Ubuntu), because in this locale sort apparently ignores the difference between hyphens and spaces. In the default C locale, however, it's broken, because in that locale all sorting is done in pure ASCII order, so that hyphen sorts after space. – Ilmari Karonen – 2016-12-10T20:22:30.330

1

Python + inflect, 97 91 89 bytes

from inflect import*
a={x:engine().number_to_words(x)for x in words}
sorted(a,key=a.get)

Used the inflect library to transform the words array of integers into their phonetic/string representation. Stored into a dictionary of k/v pairs where the keys were the numeric representation and values were the string representation. Returned the list of keys as sorted by values.

EDIT: Saved 5 and 3 bytes, thanks to ETHproductions and Alex.S!

9814072356

Posted 2016-12-01T20:20:47.513

Reputation: 11

Welcome to PPCG! You can golf this by removing spaces; for example, the second line can be a={x:inflect.engine().number_to_words(x)for x in words}.

– ETHproductions – 2016-12-02T04:06:46.397

You can save two bytes using from inflect import* and throwing out inflect. in the second line. – Alex.S – 2016-12-02T11:15:50.047

Alas, looks like this also fails to correctly sort the list 40, 44, 40000, 40804, 40004, 40204 (which should stay in that order). – Ilmari Karonen – 2016-12-10T20:13:31.863

0

Mathematica, 30 bytes

The answer below outputs a pure function which will take a list of integers as an input and sort them by their alphabetic name. Just what the doctor ordered ;)

SortBy[#~IntegerName~"Words"&]

Here is the ungolfed version:

SortBy[IntegerName[#, "Words"]&]

And here is an example usage:

SortBy[#~IntegerName~"Words"&][{0,1,2,3,4,5,6,7,8,9,10}]

Which could also be written as

SortBy[#~IntegerName~"Words"&]@{0,1,2,3,4,5,6,7,8,9,10}

They produce identical outputs - in mathematica, f[x] is equivilant to f@x.

Outputs: {8, 5, 4, 9, 1, 7, 6, 10, 3, 2}

There is a much longer answer that another user posted in Mathematica. That answer tries to correct for some small differences between the way mathematica alphebatizes numbers to better conform to the way the OP stated numbers should be alphebatized, however the things they correct for don't affect sorting order, and my answer outputs identically to theirs:

MyF = SortBy[#~IntegerName~"Words"&];
TheirF = SortBy[#, #~IntegerName~"Words"~ StringReplace~{"," -> "", "-" -> ""} &] &;
MyF[Range[-999999, 999999]] == TheirF[Range[-999999, 999999]]
(*Outputs True*)

J. Antonio Perez

Posted 2016-12-01T20:20:47.513

Reputation: 1 480

A great investigation!—unfortunately, they don't actually give the same order. TheirF correctly sorts 888 before 880,000, while MyF doesn't. Probably the issue is with the copy-pasting of the strange hyphen: your version of TheirF is probably replacing normal hyphens (of which there are none), while the actual version replaces the strange 3-byte Unicode hyphen. (It would still be interesting to see whether removing commas is necessary.) – Greg Martin – 2016-12-02T17:59:22.990

I tested it on Range[999999]. Looks like eliminating the commas is unnecessary, but replacing "[Hyphen]" with "" is definitely necessary. – ngenisis – 2016-12-02T19:28:04.140

0

Common Lisp, 113 bytes

No external libraries necessary.

(print(mapcar #'cdr(sort(loop for i in x collect(cons(format()"~r"i)i))(lambda(y z)(string-lessp(car y)(car z))))))

Output if x is '(1 2 3 4 5):

(5 4 1 3 2)

Harry

Posted 2016-12-01T20:20:47.513

Reputation: 1 189