Rearrange a number into alphabetical order

24

1

Given a non-negative integer (n), create a function that returns n in alphabetical order, according to the literal spelling of each digit in n.

Examples:

Input: 101
>> one, zero, one
>> one, one, zero
Output: 110

Input: 31948
>> three, one, nine, four, eight
>> eight, four, nine, one, three
Output: 84913

Input: 5544
>> five, five, four, four
>> five, five, four, four
Output: 5544

Input: 1234567890
Output: 8549176320

Note: the operations in the example are illustrative only and do not need to be included in the output. Only the alphabetically-sorted number needs to be returned.

This is code-golf, so the shortest code in bytes wins.

Edit: the input can be taken in any desired format that best suits your language, and the output can be produced similarly by returning from the function or printing. The input will always be a natural number (including 0) and will not contain leading 0's.

Relevant OEIS entry (A057846) found by @DomHastings

atlasologist

Posted 2016-07-07T20:49:54.217

Reputation: 2 945

1Can I also take the number as a string and output a string? – ThreeFx – 2016-07-07T21:04:00.057

1@nimi 00 .... – TuxCrafting – 2016-07-07T21:07:19.090

@atlasologist May we print the output? – xnor – 2016-07-07T21:10:39.620

@xnor returned from function or printed--either seems fine. – atlasologist – 2016-07-07T21:11:54.980

5You might want to specify that the input is in decimal, or you'll get some cheeky answers using unary... – Martin Ender – 2016-07-07T21:16:42.953

@nimi 00 doesn't need to be handled. – atlasologist – 2016-07-07T21:24:38.847

Multi digit strings "one hundred two"? – zero298 – 2016-07-08T01:07:11.030

6

This is a bit confusing: you wrote in the comments that you expect a numeric type as input and output of the function, but also that it’s okay to print the result instead. So, if the output is 849, does that mean we’re allowed to print the number 849 but not the string "849"? IMO this is just a cumbersome I/O format (bad!) on top of a perfectly fine challenge.

– Lynn – 2016-07-08T01:27:19.350

1Leading zeroes significant or not? e.g. what does 001 output? If they are significant and the result is not 1, most languages will require strings as input for the simple fact it is crude, impractical and usually nigh on impossible to ask the parser to preserve leading zeroes in base 10 literal numbers. – cat – 2016-07-08T02:56:02.007

@Cat, input will be natural numbers with no leading 0's. – atlasologist – 2016-07-08T03:38:29.203

Of course there's an OEIS entry: Obsessive Filer's Sequence

– Dom Hastings – 2016-07-08T11:32:41.377

@DomHastings wow, nice find! – atlasologist – 2016-07-08T12:03:03.070

Answers

12

Perl 6,  32  28 bytes

{+[~] .comb.sort: *.Str.uniname}
{+[~] .comb.sort: *.uniname}

Explanation:

{
  # turn the following into a Numeric
  +

  # fold the following list using string concatenation operator
  [~]

    # split $_ into individual characters
    # (implicit method call on implicit parameter)
    .comb

    .sort:
    *.uniname # sort by the Unicode name of the character (digit)
}

Test:

#! /usr/bin/env perl6
use v6.c;
use Test;

my @tests = (
  101 => 110,
  31948 => 84913,
  5544 => 5544,
  1234567890 => 8549176320,
);

# give the lambda a lexical name for clarity
my &int-sort = {+[~] .comb.sort: *.uniname}

plan 3 * @tests;

for @tests -> $_ ( :key($input), :value($expected) ) {
  put '';
  isa-ok $input, Int, "input ($input) is an Int";

  my $output = int-sort $input;

  is $output, $expected, .gist;
  isa-ok $output, Int, "output ($output) is an Int"
}
1..12

ok 1 - input (101) is an Int
ok 2 - 101 => 110
ok 3 - output (110) is an Int

ok 4 - input (31948) is an Int
ok 5 - 31948 => 84913
ok 6 - output (84913) is an Int

ok 7 - input (5544) is an Int
ok 8 - 5544 => 5544
ok 9 - output (5544) is an Int

ok 10 - input (1234567890) is an Int
ok 11 - 1234567890 => 8549176320
ok 12 - output (8549176320) is an Int

Brad Gilbert b2gills

Posted 2016-07-07T20:49:54.217

Reputation: 12 713

8

05AB1E, 12 11 10 bytes

•OWÿ¾•vy†J

Explained

•OWÿ¾•        # push sortorder (236719458)
      v       # for each number in sortorder
       y†     # filter to the front
         J    # join
              # implicitly print

Try it online

Saved 1 byte thanks to Adnan

Emigna

Posted 2016-07-07T20:49:54.217

Reputation: 50 798

8

JavaScript (ES6), 54

Edit same char count, but avoiding the global variable z

Input / output as strings

n=>[...n].sort((a,b)=>n[a]-n[b],n='9487216503').join``

Test

f=n=>[...n].sort((a,b)=>n[a]-n[b],n='9487216503').join``

function test() {
  O.textContent=f(I.value)
}

test()
<input id=I type=number value=31948 oninput='test()'>
<pre id=O></pre>

edc65

Posted 2016-07-07T20:49:54.217

Reputation: 31 086

2Love this, using the input digits as indices of the string z... – Dom Hastings – 2016-07-08T11:35:09.467

6

Haskell, 62 51 44 bytes

As @nimi suggested, using a list comprehension is shorter than composing functions:

f x=0+read[a|a<-"8549176320",b<-show x,a==b]

For reference my version:

f n=read.(=<<)(\x->filter(==x)$show n)$"8549176320"

The pointfree version is a bit longer:

f=flip(read.)"8549176320".(=<<).flip(filter.(==)).show

Straightforward: Filter the digits in the correct order and then concatenate the result.

ThreeFx

Posted 2016-07-07T20:49:54.217

Reputation: 1 435

5

Pyth, 12 10 bytes

ox`C" Ȁ\0

Not sure if it can be golfed further. Input needs to be enclosed in quotes.

2 bytes saved thanks to @isaacg!

In pythonic pseudocode:

                Q = input()
o          Q    sort(Q, key = lambda N:
  `C" Ȁ\0        repr(base256toDec(" Ȁ\0"))
 x        N         .index(N)     # 8 being absent from the number yields -1
                )

Test it here.

busukxuan

Posted 2016-07-07T20:49:54.217

Reputation: 2 728

@busukxuan I also get 14 bytes :p.

– Adnan – 2016-07-07T23:30:04.360

@Adnan revert to numbers then. It seems there isn't a way to compress these numbers... – busukxuan – 2016-07-07T23:33:04.520

2Save 2 bytes by replacing 549176320 with C" Ȁ\0 Рisaacg Р2016-07-08T02:23:11.747

@isaacg Thanks! I tried to convert it to base 256 a few times but the result was wrong. How did you do it right? – busukxuan – 2016-07-08T02:45:47.227

1You have to escape null bytes by replacing them with \0. That's probably the problem you were running into. – isaacg – 2016-07-09T15:05:30.473

4

Perl, 37 bytes

36 bytes code + 1 byte command line (-F)

say sort{8549176320=~/$b.*$a/||-1}@F

Usage example:

echo -n "04823" | perl -F -M5.010 entry.pl

Jarmex

Posted 2016-07-07T20:49:54.217

Reputation: 2 045

3

Mathematica 35 78 47 bytes

31 bytes saved thanks to a suggestion by LIAMnYP!

FromDigits@SortBy[IntegerDigits@#,IntegerName]&

IntegerDigits breaks up the number into digits which are then sorted according to their names in English. FromDigits assembles the digits into a base-10 number.


FromDigits@SortBy[IntegerDigits@#,IntegerName]&[1234567890]

8549176320

DavidC

Posted 2016-07-07T20:49:54.217

Reputation: 24 524

By using "SortBy" you don't have the problem of converting the words back to digits. FromDigits@SortBy[IntegerName]@IntegerDigits@#& – LLlAMnYP – 2016-07-08T11:44:35.123

Also Interpreter is painfully slow, so that's an added bonus. – LLlAMnYP – 2016-07-08T11:44:58.190

Fantastic improvement. – DavidC – 2016-07-08T13:18:42.060

11 bytes in Mtmca, whenever that comes into being. – Michael Stern – 2016-07-08T13:58:00.720

3

C, 142 141 117

Pass parameter as long long * to f(); the function modifies the parameter:

f(long long*n){char*c="8549176320",g[10]={0};for(;*n;*n/=10)++g[*n%10];for(;*c;++c)for(;g[*c-48]--;*n=*n*10+*c-48);}

long long is necessary since the last test case overflowed an int when sorted.

owacoder

Posted 2016-07-07T20:49:54.217

Reputation: 1 556

3

MATL, 19 bytes

Vt'8549176320'&m2$S

Try it online!

Explanation

V              % Implicitly input number. Convert to string (¹)
t              % Push copy of (¹)
'8549176320'   % Push this string (²), which defines order
&m             % Indices (³) of each element of (¹) in (²)
2$S            % Sort copy of (¹) according to (³). Implicitly display

Luis Mendo

Posted 2016-07-07T20:49:54.217

Reputation: 87 464

3

Jelly, 11 bytes

“U1°ŀ”OṾf@€

Try it here.

Explanation

“U1°ŀ”O       Get the Unicode ordinals of “U1°ŀ”
                (all of which are coincidentally single bytes
                in the Jelly code page!)
              The result is [85, 49, 176, 320].
       Ṿ      Uneval. This gets us the string “85,49,176,320”.
        f@€   For each char in this string, extract all chars
                from the first command line argument that
                equal it.

Lynn

Posted 2016-07-07T20:49:54.217

Reputation: 55 648

2

Python 2 - 95 bytes

def s(n):
    l=list("8549176320")
    return "".join(sorted(list(n),key=lambda x: l.index(x)))

Attempting further golfing...I think the line 2 is unnecessary and this can become 1 lambda.

EDIT: 49 char version in comments, thx to xnor and vaultah for help.

Jeremy

Posted 2016-07-07T20:49:54.217

Reputation: 521

lambda n:''.join(sorted(\n`,key="8549176320".find))` – vaultah – 2016-07-07T21:11:24.313

4@vaultah Nice solution, you should post it! I think you can omit the 8 so that the find gives -1. – xnor – 2016-07-07T21:13:19.697

1ooh that's clever @xnor. The shortest I got it to was lambda n: "".join(sorted(n,key="549176320".find)), which is really similar to what you suggested, vaultah. You should post it! – Jeremy – 2016-07-07T21:17:25.697

1@Jeremy You should edit that version into your post. – James – 2016-07-07T22:01:10.763

2

At least get rid of the superfluous whitespace... Indentation can be done with a single space. Also this is invalid, because the OP stated that output must be a numeric type.

– Mego – 2016-07-07T23:29:07.467

@vaultah That fails for values above sys.maxint, because repr(long_value) appends an L to the end. – Mego – 2016-07-07T23:30:42.090

Needlessly long imo but +1 for a beginner :) – cat – 2016-07-08T02:23:22.200

@Mego No need to use Python 2. – cat – 2016-07-08T17:33:07.243

2

-- Oracle 11 (SQL): 164 bytes

  SELECT LISTAGG(DECODE(s,0,'zero',TO_CHAR(TO_DATE(s,'j'),'jsp')),',')WITHIN GROUP(ORDER BY 1)FROM(SELECT SUBSTR(&1,level,1)s FROM dual CONNECT BY LEVEL<=LENGTH(&1));

Long form and explanation

  SELECT LISTAGG(DECODE(s,0,'zero',TO_CHAR(TO_DATE(s,'j'),'jsp')),',') WITHIN GROUP (ORDER BY 1)
  FROM ( SELECT SUBSTR(&1,level,1)s FROM dual
           CONNECT BY LEVEL <= LENGTH(&1)
        );

Get the input as parameter to script:

  SELECT &1 FROM dual

"create" rows by using connect by based on length of input:

  CONNECT BY LEVEL <= LENGTH(&1)

Rip out each digit from the string for each position:

  SELECT SUBSTR(&1,level,1)s FROM dual

Convert the digit to Julian date, and back to Char to get spelling:

  TO_CHAR(TO_DATE(s,'j'),'jsp')

Check for zero - special case.

  DECODE(s,0,'zero'

Use LISTAGG function to concatenate rows back into a single row list, comma delimited, ordered alphabetically

  LISTAGG(DECODE(s,0,'zero',TO_CHAR(TO_DATE(s,'j'),'jsp')),',') WITHIN GROUP (ORDER BY 1)

Always fun trying to tweak SQL for things like this ... :) really tests my knowledge of the bugger ...

Ditto

Posted 2016-07-07T20:49:54.217

Reputation: 495

1

Racket, 142 130 bytes

(λ(n)(string->number(list->string(sort(string->list(~a n))char<? #:key(λ(m)(string-ref "9487216503"(-(char->integer m)48)))))))

Of which conversions are more than almost half of the length (76 64 bytes).

Steven H.

Posted 2016-07-07T20:49:54.217

Reputation: 2 841

(+ 1 answer) for Racket! – cat – 2016-07-08T02:21:05.517

@cat It's useful for me to keep practicing Racket, since it's a way to maintain functional programming knowledge while working on these horribly procedural legacy Java (and slightly-less-legacy Python) programs left to me by my co-workers. I could rant about how having objects does not necessarily make a program object-oriented, but instead of doing that I'll just keep golfing my problems away in Racket. – Steven H. – 2016-07-08T03:05:45.040

Hmm... I definitely sympathise, and it's possible and fun to write functional Python, but Java's just Fawful. Maybe you can get your superiors to let you use Scala for the implementation and Java just as glue. :) – cat – 2016-07-08T03:34:11.317

By the way, if you like Forth and your eyes get a little tired from reading Lisp inside-out, you should check out Factor, which is Lisp and the CLOS but in a Forth-y postfix and point-free disguise.

– cat – 2016-07-08T03:35:06.617

1

Ruby, 60 bytes

->n{n.to_s.chars.sort_by{|c|'8549176320'.index c}.join.to_i}

Value Ink

Posted 2016-07-07T20:49:54.217

Reputation: 10 608

1

TSQL, 260 bytes

Used reversed bubble sort to avoid refering to the length, to save some bytes

Golfed:

DECLARE @ varchar(99)=101

,@i INT=99,@j INT=98WHILE @i>1SELECT
@=IIF(CHARINDEX(x,'598327614')>CHARINDEX(y,'598327614'),STUFF(STUFF(@,@j,1,x),@i,1,y),@),@i-=IIF(@j=1,1,0),@j=IIF(@j=1,@i,@j-1)FROM(SELECT
SUBSTRING(@,@i,1)x,SUBSTRING(@,@j,1)y)z
PRINT @

Ungolfed:

DECLARE @s BIGINT=1234567890

DECLARE @ char(99)=@s,@i INT=99,@j INT=98
WHILE @i>1
  SELECT 
    @=IIF(CHARINDEX(x,'236719458')>CHARINDEX(y,'236719458'),
        STUFF(STUFF(@,@j,1,x),@i,1,y),@), 
    @i-=IIF(@j=1,1,0),
    @j=IIF(@j=1,@i,@j-1)
  FROM(SELECT SUBSTRING(@,@i,1)x,SUBSTRING(@,@j,1)y)z
PRINT CAST(@ as bigint)

Insisting on using integer types as input and output added 37 bytes

t-clausen.dk

Posted 2016-07-07T20:49:54.217

Reputation: 2 874

DECLARE @ varchar(99)=101 0.o does 101 get turned to a string automatically? – cat – 2016-07-08T13:30:23.607

Also, stuff is an objectively awful function name. squash or shove or pack would be better :P – cat – 2016-07-08T13:31:50.077

@cat yes, it gets converted into a string automatically, but that would be cheating according to the descriptino. I agree, stuff is a silly name – t-clausen.dk – 2016-07-08T15:03:23.733

1I mean, we might as well just call every function stuff cause that's what functions do: they do stuff. Then your code can look like stuff(stuff(4, 5, stuff), stuff(stuff()).(stuff())()); stuff(stuff) – cat – 2016-07-08T19:24:45.397

1

ClojureScript, 45 bytes

#(apply str(sort-by(vec"9487216503")(str %)))

Uses some screwy string->int conversion from Javascript leak through, so it's not valid Clojure.

MattPutnam

Posted 2016-07-07T20:49:54.217

Reputation: 521

1

Firebird, 317 bytes

Golfed:

select list(s,'')from(with recursive q as(select 1 p,substring(:a from 1 for 1)s from rdb$database q union all select q.p+1 p,substring(:a from q.p+1 for 1)s from q where q.p<char_length(:a))select s from q order by iif(s=8,0,iif(s=5,1,iif(s=4,2,iif(s=9,3,iif(s=1,4,iif(s=7,5,iif(s=3,7,iif(s=2,8,iif(s=0,9,6))))))))))

Ungolfed:

select list(s, '')
from (
   with recursive q as (
      select 1 as p, substring(:a from 1 for 1) s
      from rdb$database q
      union all
      select q.p + 1 as p, substring(:a from q.p + 1 for 1) as s
      from q
      where q.p < char_length(:a)
   )
   select s
   from q
   order by iif(s = 8, 0,
               iif(s = 5, 1,
                  iif(s = 4, 2,
                     iif(s = 9, 3,
                        iif(s = 1, 4,
                           iif(s = 7, 5,
                              iif(s = 3, 7,
                                 iif(s = 2, 8,
                                    iif(s = 0, 9, 6)))))))))
)

There's no split functionality in Firebird. Instead I created a recursive query to get the next character over and over. Then reselect those while sorting by our proper order. Finally concatenate those results back together in a list. Override the default comma delimiter with blank. I could save 11 bytes by creating a new dummy table instead of rdb$database but I thought that may be against the rules.

Paul

Posted 2016-07-07T20:49:54.217

Reputation: 328

1

ZX Spectum, machine code, 53 48 47 45 44 bytes

    org 49200 ; #c030

; table converts ascii to alfabetical order
; start from BASIC with any number as : PRINT "1234567890" AND USR 49208

convtab defb 249 ; zero defb 244 ; one defb 248 ; two defb 247 ; three defb 2+205 ; four defb 1+205 ; five defb 246 ; six defb 245 ; seven ; defb 0 ; eight ; defb 3 ; nine ; last 2 conversions hidden in call-command

start Call #2bf1    ; fetch stackindex
    call #2ab2 ; store back
    ld h,#c0    ; set highbyte of table


Sort Push de
loop ld b,d
    ld c,e
    inc de
    ld a,(bc)   ; fetch number
    Ld l,a
    ld a,(de)
    cp 34       ; endmarker "
    Jr z,exit   ; end reached?
    push hl     ; save number
    ld l,a
    Ld a,(hl)   ; convert second number
    pop hl
    cp (hl)     ; compare numbers
    jr nc,loop  ; in order, no swap
swap ld a,(bc)  ; swap original numbers
    ld l,a
    ld a,(de)
    ld (bc),a
    ld a,l
    ld (de),a
Exit pop de
    Ret z
    jr sort     ; check number for order

Johan Koelman

Posted 2016-07-07T20:49:54.217

Reputation: 21

With Gnome-sort it can be shortened and table can be 1 byte shorter. New version to come... – Johan Koelman – 2016-07-19T10:25:29.317

Gnome-sort here is longer, but other optimizations. – Johan Koelman – 2016-07-19T13:04:30.060

0

PHP, 107 bytes

function($a){usort($a,function($a,$b){return($z=array_flip([8,5,4,9,1,7,6,3,2,0]))[$a]-$z[$b];});return$a;}

Try it online!

Uses a user-defined comparison function to adjust the sorting order.

Output

101         110
31948       84913
5544        5544
1234567890  8549176320

640KB

Posted 2016-07-07T20:49:54.217

Reputation: 7 149

0

Factor, 128

[ 10 base> [ 48 - ] { } map-as dup [ number>text ] map zip [ second first ] sort-with [ first ] map [ 48 + ] ""map-as 10 >base ]

Hooray for builtins! :D

cat

Posted 2016-07-07T20:49:54.217

Reputation: 4 989

0

PHP, 126 bytes

As far as I know php doesn't have any builtins that would really help with this (the best I could do using a usort(str_split()) was 5 bytes longer) so the only thing I'm happy within this answer is the games played with $i to save a couple of bytes on the itteration.

<?php for($i=-1;$i<9;)$a[++$i]=preg_replace("/[^$i]/","",$argv[1]);array_multisort([9,4,8,7,2,1,6,5,0,3],$a);echo implode($a);

user55641

Posted 2016-07-07T20:49:54.217

Reputation: 171

0

APL, 23 bytes

{⍎n['8549176320'⍋n←⍕⍵]}

Explanation:

  • n←⍕⍵: get the string representation of n and store it in n
  • '8549176320'⍋: find a permutation of n that sorts n given the order 8549176320.
  • n[...]: reorder n by that permutation
  • : evaluate the result (to turn it back into a number)

marinus

Posted 2016-07-07T20:49:54.217

Reputation: 30 224

Since I/O may be strings, you can remove and . Convert to tradfn by removing { and } and substituting for . Finally, remove 0 as unlisted sorts at the end: n['854917632'⍋n←⍞] – Adám – 2016-08-29T06:07:43.377

0

Clojure, 53 bytes

Well, list comprehension idea from Haskell solution seems to be the shortest:

#(apply str(for[p"8549176320"b(str %):when(= p b)]p))

My original approach is 1 byte longer:

#(apply str(sort-by(zipmap"549176320"(range))(str %)))

You can see both function online here: https://ideone.com/afac5n

cliffroot

Posted 2016-07-07T20:49:54.217

Reputation: 1 080

0

Common Lisp, 104

(lambda(n)(#1=parse-integer(sort(format()"~A"n)'string<= :key(lambda(u)(format()"~R"(#1#(string u)))))))

Ungolfed

(lambda (n)
  (parse-integer
   (sort (format nil "~A" n)
         #'string<=
         :key (lambda (u) (format nil "~R" (parse-integer (string u)))))))

Convert integer as string, sort characters using the string<= comparison while using a custom :key function which converts a given character as the English representation of the numerical value it represents. Usually I would not use a key function which does as much as this one, but it costs less in bytes than decorate/sort/undecorate.

coredump

Posted 2016-07-07T20:49:54.217

Reputation: 6 292

0

Python 3, 234 bytes

This is a direct translation of my Factor answer, just for fun.

def f(n):
 s=list(map(int,str(n)))
 return int("".join(list(map(str,list(map(lambda x:x[1],sorted(list(zip(list(map(lambda t:{0:"zero",1:"one",2:"two",3:"three",4:"four",5:"five",6:"six",7:"seven",8:"eight",9:"nine"}[t],s)),s)))))))))

The semantics of the evaluation of "lazy" map and zip objects is the most subtle hard-to-find-bug-inducing piece of genuine horse excrement in the universe. Sometimes, s = map(f, x) won't allow s to be used properly or at all.

cat

Posted 2016-07-07T20:49:54.217

Reputation: 4 989

0

Python 3, 74 bytes

lambda x:''.join(i[1]for i in sorted(['9487216503'[int(j)],j]for j in x))

8BitTRex

Posted 2016-07-07T20:49:54.217

Reputation: 9

You might be able to save some bytes by using a lambda – Daniel – 2016-07-09T21:09:37.183

0

Pyke, 14 bytes

.#uЀB`@

Try it here!

Blue

Posted 2016-07-07T20:49:54.217

Reputation: 26 661

0

Python 2.7.11, 67 bytes

lambda n:''.join(sorted(list(n),key=lambda s:"9487216503"[int(s)]))

Takes a string as input and outputs a string.

Daniel

Posted 2016-07-07T20:49:54.217

Reputation: 6 425

0

C, 80 bytes

Takes a string containing a number in base 10 and prints to stdio:

F(char*i){for(char*p,d,*o="8549176320";*o;++o)for(p=i;d=*p++;d-*o||putchar(d));}

Stefano Sanfilippo

Posted 2016-07-07T20:49:54.217

Reputation: 1 059