26
\$\begingroup\$

Input:

  • An array containing three integers: 0, 1 and 2 in any order (i.e. [2, 0, 1])
  • And a string of length >= 2 only containing alphabetic letters (both lower- and uppercase) and digits (i.e. a1B2c3)

Output:

Based on the array we sort and output the string.
How does this work?

  • The array indicates the order precedence of a-z, A-Z and 0-9, the first being 0; second being 1; and third being 2.
  • The individual characters of the string can then be ordered based on that.

Example:

  • Array: [2, 0, 1]
  • String: a1B2c3

Based on the array, we know our order precedence is 0-9a-zA-Z.
Based on that, we can convert and output the string: 123acB.

Challenge rules:

  • For the array you can choose to use 0-indexed or 1-indexed input, so [3, 1, 2] is also a valid input if you prefer to use 1-indexed arrays.
  • The string (both input and output) only contains valid characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.
  • If your language doesn't support arrays (or if you choose to), you are free to use strings instead of arrays for the first parameter (i.e. 012, [0,1,2], etc.).

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, please add an explanation if necessary.

Test cases:

[2, 0, 1]  &  a1B2c3             ->   123acB
[2, 1, 0]  &  aAaA909UuHWw9gh2   ->   02999AAHUWaaghuw
[2, 1, 0]  &  6Bx43              ->   346Bx
[1, 0, 2]  &  jfjf33g            ->   ffgjj33
[0, 2, 1]  &  AbC13              ->   b13AC
[1, 2, 0]  &  Qfl0l              ->   Q0fll
[0, 1, 2]  &  9870abcABC         ->   abcABC0789
[0, 2, 1]  &  test123            ->   estt123
[2, 0, 1]  &  WHAT               ->   AHTW
[2, 0, 1]  &  WhAt               ->   htAW
[1, 0, 2]  &  102BACbac          ->   ABCabc012
\$\endgroup\$
3
  • \$\begingroup\$ Would "123" be a valid format for the first parameter? \$\endgroup\$
    – user45941
    Commented Jul 13, 2016 at 8:04
  • \$\begingroup\$ Related: Imitate an ordering \$\endgroup\$
    – xnor
    Commented Jul 13, 2016 at 8:06
  • \$\begingroup\$ @Mego Yeah why not. It's not affecting the main part of the challenge. I've edited my question to reflect the change. Feel free to use 123, 012, [0,1,2], [0, 1, 2], 0;1;2 or whichever you prefer. \$\endgroup\$ Commented Jul 13, 2016 at 8:14

24 Answers 24

8
\$\begingroup\$

Python 2, 67 66 bytes

lambda s,k:`sorted(s,key=lambda c:`k.index(3-ord(c)/32)`+c)`[2::5]

Test it on Ideone.

\$\endgroup\$
7
\$\begingroup\$

JavaScript (ES6), 87 bytes

(a,s)=>a.map(n=>[...s].sort().join``.replace([/[^a-z]/g,/[^A-Z]/g,/\D/g][n],``)).join``

If the input array gave the order, rather than the precedence, of the three ranges (this only makes a difference for [1, 2, 0] and [2, 1, 0] whose effects are swapped) then this would have worked for 80 bytes:

(a,s,o=c=>a[(c<'a')+(c<'A')])=>[...s].sort((a,b)=>o(a)-o(b)||(a>b)-(a<b)).join``

I misread the question and still got 7 upvotes with this. Feel free to remove your upvotes and give them to @CharlieWynn instead, who came up with the best correction to my approach.

(a,s)=>a.map(n=>s.replace([/[^a-z]/g,/[^A-Z]/g,/\D/g][n],``)).join``
\$\endgroup\$
5
  • 3
    \$\begingroup\$ Ooh, very interesting solution! I was thinking of a different ES6 answer to use Array.sort's optional function parameter but this woks way better. \$\endgroup\$ Commented Jul 13, 2016 at 8:20
  • 1
    \$\begingroup\$ I really like this solution, but I think it fails test 2, 3 and probably others. I guess you're supposed to sort each of the three segments? \$\endgroup\$ Commented Jul 13, 2016 at 12:53
  • \$\begingroup\$ @CharlieWynn Sorry, I must have misread the question. (It's a common fault of mine.) \$\endgroup\$
    – Neil
    Commented Jul 13, 2016 at 18:50
  • \$\begingroup\$ @Neil, I don't think the question made it very clear to sort the array, just noticed the test cases seemed to have that feature. \$\endgroup\$ Commented Jul 14, 2016 at 17:34
  • \$\begingroup\$ @CharlieWynn Most of the test cases appeared to be already sorted w.r.t. lower/upper/numeric portions anyway... \$\endgroup\$
    – Neil
    Commented Jul 14, 2016 at 18:48
5
\$\begingroup\$

05AB1E, 15 14 12 bytes

Code:

v²žK26ôyèÃ{?

Explanation:

v             # For each in the input array.
  žK          #   Push a-zA-Z0-9.
    26ô       #   Split into pieces of 26.
       yè     #   Get the element-th element of the array.
 ²       Ã    #   Keep the characters of that element from the second input.
          {?  #   Sort pop and print without a newline.

Uses the CP-1252 encoding. Try it online!.

\$\endgroup\$
1
  • \$\begingroup\$ This can be 10 bytes now by removing the ² and using instead of 26. \$\endgroup\$ Commented Aug 30, 2019 at 11:06
5
\$\begingroup\$

Jelly, 13 bytes

2_ịØWs26¤Ff@€

Try it online! or verify all test cases.

How it works

2_ịØWs26¤Ff@€  Main link. Arguments: k (permutation of [0, 1, 2]), s (string)

2_             Subtract the integers in k from 2, mapping [0, 1, 2] -> [2, 1, 0].
        ¤      Combine the three links to the left into a niladic chain.
   ØW          Yield the string following string.
               'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_'
     s26       Split it into chunks of 26 chars, i.e., ['A...Z', 'a...z', '0...9'].
  ị            Retrieve the chunks from the right result at the indices of the
               left result. The indices of the chunks are modular and 1-based;
               1 retrieves 'A...Z', 2 retrieves 'a...z', and 3 retrieves '0...9'.
         F     Flatten the resulting array of strings.
          f@€  Filter (swapped, each); for each character in the constructed
               string, select all occurrences of that character from s.
\$\endgroup\$
5
\$\begingroup\$

Pyth, 17 16 15 bytes

s@RSz@L[GrG1`UT

Test suite.

       [          array literal containing...
        G           the alphabet (lowercase)
         rG1        the alphabet, converted to uppercase
            `UT     inspect-range-10, generating the range [0,10) and
                      stringifying it, resulting in a string that contains no
                      letters and all numbers (so equivalent to '0123456789' for
                      filtering)
                    this creates ['ab...z', 'AB...Z', '01...9']

     @L           map over first (implicit) input (the ordering array) and take
                   the nth element in this array for each item
                   this gives us ['01...9', 'ab...z', 'AB...Z']

   Sz             take another line of input as a string and sort it, and then...
 @R               map over intersection: filter the line of input over presence
                    in each element in the new array
                    this results in ['123', 'ac', 'B']

s                 concatenate all and implicitly output

Thanks to @FryAmTheEggman for a byte and @Jakube for another!

\$\endgroup\$
4
  • \$\begingroup\$ You can use 'UT instead of s'MT. \$\endgroup\$
    – Jakube
    Commented Jul 14, 2016 at 9:04
  • \$\begingroup\$ @Jakube I'm using a backtick, not a single quote. But 'UT is an error, and `UT doesn't result in the same string. \$\endgroup\$
    – Doorknob
    Commented Jul 14, 2016 at 9:36
  • \$\begingroup\$ Yes, I meant a backtick. But a backtick is hard to write in the comments. Yes, it generates a different string, but it shouldn't matter. The generated string contains all digits and no letters. \$\endgroup\$
    – Jakube
    Commented Jul 14, 2016 at 9:44
  • \$\begingroup\$ @Jakube Oh, I see. That's clever; thanks! \$\endgroup\$
    – Doorknob
    Commented Jul 14, 2016 at 10:48
5
\$\begingroup\$

Javascript es6 77 bytes

(a,s)=>a.map(o=>s.match([/[a-z]?/g,/[A-Z]?/g,/\d?/g][o]).sort().join``).join``

//test
f=(a,s)=>a.map(o=>(s.match([/[a-z]/g,/[A-Z]/g,/\d/g][o])||[]).sort().join``).join``


f([2, 0, 1], "a1B2c3")             == "123acB" &&
f([2, 1, 0], "aAaA909UuHWw9gh2")   == "02999AAHUWaaghuw" &&
f([2, 1, 0], "6Bx43")              == "346Bx" &&
f([1, 0, 2], "jfjf33g")            == "ffgjj33" &&
f([0, 2, 1], "AbC13")              == "b13AC" &&
f([1, 2, 0], "Qfl0l")              == "Q0fll" &&
f([0, 1, 2], "9870abcABC")         == "abcABC0789" &&
f([0, 2, 1], "test123")            == "estt123" &&
f([2, 0, 1], "WHAT")               == "AHTW" &&
f([2, 0, 1], "WhAt")               == "htAW" &&
f([1, 0, 2], "102BACbac")          == "ABCabc012"
\$\endgroup\$
3
  • \$\begingroup\$ Stole @Neil's very neat regex array idea \$\endgroup\$ Commented Jul 13, 2016 at 13:03
  • \$\begingroup\$ By adding ?s to each regex, this ensures that the match returns results (mostly empty strings, but they disappear anyway), avoiding the (||[]), thus saving you 3 bytes overall. \$\endgroup\$
    – Neil
    Commented Jul 13, 2016 at 20:38
  • \$\begingroup\$ @Neil wonderful, thanks.. I wasn't sure why you had those in yours :P \$\endgroup\$ Commented Jul 14, 2016 at 17:33
4
\$\begingroup\$

TSQL, 199 191 bytes

Golfed:

DECLARE @i varchar(99)='abA7B34',@s char(3)='213'

,@ varchar(99)=''SELECT @+=n FROM(SELECT top 99n FROM(SELECT top 99substring(@i,row_number()over(order by 1/0),1)n FROM sys.messages)c ORDER BY CHARINDEX(CHAR(ascii(n)/32+48),@s),n)d SELECT @

Ungolfed:

DECLARE @i varchar(99)='abA7B34'
-- 1 numbers, 2 upper case, 3 lower case
DECLARE @s char(3)='213'


,@ varchar(99)=''
SELECT @+=n
FROM
  (
    SELECT top 99 n 
    FROM
      (
         SELECT top 99substring(@i, row_number()over(order by 1/0), 1)n
         FROM sys.messages
      )c
    ORDER BY CHARINDEX(CHAR(ascii(n)/32+48),@s),n
  )d

SELECT @

Fiddle

\$\endgroup\$
3
\$\begingroup\$

APLX, 19 bytes

s[(∊(⎕a⎕A⎕D)[a])⍋s]

⎕a⎕A⎕D lower upper digits

()[a] reorder according to array a

flatten

()⍋s according to that "alphabet", give the indices that would sort string s

s[] use that to reorder s

\$\endgroup\$
2
  • \$\begingroup\$ Too bad Dyalog APL does not have ⎕a and the the uppercase to lowercase translation takes up a lot of bytes in the solution :-) Not that I am not suggesting for Dyalog APL to include ⎕a given that its usefulness would be pretty much reduced to code-golfing challenges, as far as I can tell. \$\endgroup\$
    – lstefano
    Commented Jul 20, 2016 at 13:07
  • \$\begingroup\$ @lstefano I don't like ⎕a, because it is a case-sensitive quad name. Much better (for golfing and in general) what I'm lobbying for; to get and to fold case on character data, just like in K. Then we'll have ⌊⎕A instead of ⎕a. \$\endgroup\$
    – Adám
    Commented Jul 20, 2016 at 14:32
2
\$\begingroup\$

Python 2, 121 Bytes

lambda a,s:"".join(sum([[sorted(filter(eval(u),s))for u in["str.islower","str.isupper","str.isdigit"]][i]for i in a],[]))
\$\endgroup\$
2
\$\begingroup\$

Clojure, 74 bytes

#(apply str(mapcat sort(for[i %](re-seq([#"[a-z]"#"[A-Z]"#"[0-9]"]i)%2))))

For each value in first list, gets appropriate regex and apply it to the input string. The result is a list of lists of symbols which match the regex. Then sort each one and concatenates the result into one list and transform it to string.

You can see it online here: https://ideone.com/dqAkxg

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

Retina, 43 39 bytes

Byte count assumes ISO 8859-1 encoding. The trailing linefeed is significant.

2=`.
!$&"
T04`¶d`#^@%
O`\W?.
O`.\w+
\W

Input is expected to be the sort order as a zero-based list without delimiters on the first line, and the string to be sorted on the second line, e.g.

120
fOo42BaR

Try it online!

Explanation

I will use the above input example to walk you through the code:

120
fOo42BaR

Stage 1: Substitution

2=`.
!$&"

The regex itself is just . (matches any non-linefeed character), which is surrounded with !...". However, the 2= is a limit telling Retina to apply the substitution only to the second match of the regex. So we get this:

1!2"0
fOo42BaR

Stage 2: Transliteration

T04`¶d`#^@%

A transliteration stage simply does a character-by-character substitution. The represents a linefeed and d expands to 0123456789 (although we can ignore all digits after 2). That means, this transliteration corresponds to the following mapping:

¶012
#^@%

The 04 at the front are two limits, which together indicate that only the first four characters from this set should be transliterated. That happens to be the digits on the first line, as well as the linefeed separating the two lines, so we get this:

@!%"^#fOo42BaR

At the front of the string we've now got three pairs of these characters:

@!
%"
^#

Note that the second characters of the pairs are simply in their normal ASCII order (and will always be the same). We'll use these later to sort the groups of characters in the main input into the required order.

The first characters are bit more interesting: their significance is that % comes before digits in the ASCII table, @ comes before upper case letters (but after digits), and ^ comes before lower case letters (but after upper case letters). This will help us group the position markers (i.e. the second character in each pair) with the right set of characters.

Stage 3: Sort

O`\W?.

This is a simple sort stage. It matches two characters if the first one isn't a word character (thereby matching all three pairs I just talked about) or a single character otherwise (matching each character of the main input individually), and sorts those strings. This has two purposes: it brings the characters within each group in the correct order (and since sorting is stable, this order won't be messed up in the next stage), and it due to the %@^ markers, it inserts the pairs in the right positions:

%"24@!BOR^#afo

Stage 4: Sort

O`.\w+

This stage sorts all matches of the .\w+ regex which, due to greediness, matches one position marker (i.e. one of !"#) together with all the word characters after it. That is, it sorts these three strings, whose order is determined solely by the marker character:

"24 !BOR #afo

While this shuffles around those markers (while leaving the other three markers in place), most importantly it brings the digits and letters in the correct order:

%!BOR@"24^#afo

Stage 5: Substitution

\W

All that's left is a little clean-up, where we remove all the markers by matching them and replacing them with nothing.

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

Ruby, 56 bytes

Ported from @Dennis answer.

->a,s{s.chars.sort_by{|c|a.index(3-c.ord/32).to_s+c}*''}

An alternate 58 bytes solution that I like better, inspired by @Neil and modified slightly from his answer.

->a,s{a.map{|i|s.scan([/[a-z]/,/[A-Z]/,/\d/][i]).sort}*''}

Try either version online! (commented-out version is the alternate solution)

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

JavaScript (ES6), 65

Note: 'natural' ASCII order is 0-9, A-Z, a-z, that is just the opposite of the OP 0,1,2. So

  • order the string adding invalid chars to separate runs
  • split it in 3 segmenents - invalid chars mark each
  • get segments one by one in the requested order
  • reassemble
s=>w=>w.map(w=>[...'^@'+s].sort().join``.split(/\W/)[2-w]).join``

F=s=>w=>w.map(w=>[...'^@'+s].sort().join``.split(/\W/)[2-w]).join``

;[['201','a1B2c3','123acB']
,['210','aAaA909UuHWw9gh2','02999AAHUWaaghuw']
,['210','6Bx43','346Bx']
,['102','jfjf33g','ffgjj33']
,['021','AbC13','b13AC']
,['120','Qfl0l','Q0fll']
,['012','9870abcABC','abcABC0789']
,['021','test123','estt123']
,['201','WHAT','AHTW']
,['201','WhAt','htAW']
,['102','102BACbac','ABCabc012']]
.forEach(t=>{
  var w=t[0],s=t[1],k=t[2], r=F(s)([...w])
  console.log(w,s,r,(r==k?'OK':'KO (expected '+k+')'))
})

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

Haskell, 62 63 bytes

a#b=[c|i<-b,c<-[' '..],d<-a,d==c,div(fromEnum c)16==[6,4,3]!!i]

Usage example: "cD12ab" # [2,0,1] -> "12abcD".

How it works:

i<-b                                  -- loop i through the input array
   [c|   c<-[' '..]]                  -- loop through all chars c
       d<-a                           -- loop through all chars d in the input string
       d==c                           -- and keep those that are in the input string
       div(fromEnum c)16==[6,4,3]!!i  -- and where the the ascii value divided by
                                      -- 16 equals the number from [6,4,3] indexed
                                      -- by the current i

Edit: @Christian Sievers found a bug. Thanks! Fixed for 1 additional byte.

\$\endgroup\$
2
  • \$\begingroup\$ What about chars occuring more than once? \$\endgroup\$ Commented Jul 26, 2016 at 2:10
  • \$\begingroup\$ @ChristianSievers: you're right, that's a bug. Fixed. Thanks you! \$\endgroup\$
    – nimi
    Commented Jul 26, 2016 at 5:26
2
\$\begingroup\$

Stax, 15 bytes

┐°!'àÉgYg8∟╗`╖ë

Run and debug it online

This 15 byte submission is packed into a variant of the CP437 character set. The corresponding ascii representation takes 18 bytes:

EVlVd+26/s@:fs{[Io

Pretty sure it can be further trimmed down though.

E                   Put the two inputs on main stack
 Vl                 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
   Vd               "0123456789"
     +              Concatenate
      26/           Partition to blocks of size 26 (array `a`)
         s@         Index array `a` with the input index array
           :fs      Flatten to get a string `s`
              {[Io  Order the input string
                        Using the char array `s` as the key
                    Implicit output

VlVd+ can also be VLA|(, which left rotates the 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ by ten elemenets. The whole code can also be VlVd+26/,e@:f,{[Io, which reads the input stack twice instead of reading them all at the beginning to the main stack, and uses a different (more traditional) input format, as shown in this.

\$\endgroup\$
1
  • \$\begingroup\$ You can remove the E, but it doesn't change bytecount. \$\endgroup\$
    – Razetime
    Commented Dec 15, 2020 at 9:53
1
\$\begingroup\$

Dyalog APL, 22 bytes

s[s⍋⍨∊(819⌶⎕A)⎕A⎕D[a]]

(819⌶⎕A) fold the uppercase alphabet to lowercase

()⎕A⎕D[a] lower upper digits reordered according to array a

flatten

s⍋⍨ for string s, get the indices that would sort s according to that "alphabet"

s[] use that to reorder s

\$\endgroup\$
3
  • \$\begingroup\$ mmm.... 819⌶ only exists in the unicode version of Dyalog APL. So I would surmise that the byte count should be multiplied by 2 since the input is effectively composed of Unicode entry points.Or my understanding of the byte counting for APL submissions is wrong? \$\endgroup\$
    – lstefano
    Commented Jul 20, 2016 at 13:10
  • \$\begingroup\$ @lstefano The Unicode edition is able to load Classic workspaces, right? \$\endgroup\$
    – Adám
    Commented Jul 20, 2016 at 14:34
  • \$\begingroup\$ That's sneaky ;-) \$\endgroup\$
    – lstefano
    Commented Jul 20, 2016 at 14:37
1
\$\begingroup\$

PowerShell v2+, 107 bytes

param($n,[char[]]$s)-join(-join(($s=$s|sort)|?{$_-ge97}),-join($s|?{$_-in65..96}),-join($s|?{$_-lt58}))[$n]

I'm exploring algorithms using regex, but thus far they all seem longer.

Takes input as explicit array $n (see examples below) and string $s which is immediately cast to a char-array. We're then constructing three elements of a new dynamic array, each of them encapsulated with a -join:
- (($s=$s|sort)|?{$_-ge97})
- ($s|?{$_-in65..96})
- ($s|?{$_-lt58})

The first we take $s and run it through Sort-Object. Thankfully, since we've already cast it as a char-array, it's case-sensitive sorting. That gets re-saved into $s and then piped to a Where-Object with a clause of greater than 97 (i.e., ASCII lowercase a-z). The second is for A-Z and the third for 0-9.

Thus we now have an array of strings, where each string is composed one of the three character types and is sorted. We slice that with [$n] and then -join the result together to form our final output string. That is left on the pipeline and printing is implicit.

Test Cases

PS C:\Tools\Scripts\golfing> $test = (@(2,0,1),'a1B2c3'), (@(2,1,0),'aAaA909UuHWw9gh2'), (@(2,1,0),'6Bx43'), (@(1,0,2),'jfjf33g'), (@(0,2,1),'AbC13'), (@(1,2,0),'Qfl0l'), (@(0,1,2),'9870abcABC'), (@(0,2,1),'test123'), (@(2,0,1),'WHAT'), (@(2,0,1),'WhAt'), (@(1,0,2),'102BACbac')

PS C:\Tools\Scripts\golfing> $test |%{"($($_[0]-join',')) & $($_[1])".PadRight(28)+" -> " + (.\post-determined-array-sorting.ps1 $_[0] $_[1])}
(2,0,1) & a1B2c3             -> 123acB
(2,1,0) & aAaA909UuHWw9gh2   -> 02999AAHUWaaghuw
(2,1,0) & 6Bx43              -> 346Bx
(1,0,2) & jfjf33g            -> ffgjj33
(0,2,1) & AbC13              -> b13AC
(1,2,0) & Qfl0l              -> Q0fll
(0,1,2) & 9870abcABC         -> abcABC0789
(0,2,1) & test123            -> estt123
(2,0,1) & WHAT               -> AHTW
(2,0,1) & WhAt               -> htAW
(1,0,2) & 102BACbac          -> ABCabc012
\$\endgroup\$
1
\$\begingroup\$

32-bit x86 machine code, 70 bytes

In hex:

fc31c031c95189e3ac84c0740a34cf0404880c0341ebf189fe9160ac88c2c0e805d788c652ac88c2c0e805d788c658740e6639d076029241aa92aa4e4febdc85c96175d658c3

This procedure expects character class sorting order to be a 3-char (0..2) NULL-terminated string in ESI and the string to sort in EDI. Sorting is done in-place using extremely sub-optimal (performance-wise) version of bubble sort.

0:  fc                  cld
1:  31 c0               xor eax, eax
3:  31 c9               xor ecx, ecx
5:  51                  push ecx        ;Allocate 4 bytes on the stack
6:  89 e3               mov ebx, esp    ;char EBX[4]
_loop0:                                 ;Parsing class order string
8:  ac                  lodsb
9:  84 c0               test al,al      ;Break on NULL
b:  74 0a               jz _break0
d:  34 cf               xor al, 0xCF    ;AL=~atoi(AL)
f:  04 04               add al, 4       ;'0'->3, '1'->2, '2'->1
11: 88 0c 03            mov [ebx+eax], cl    ;EBX[AL]=CL
14: 41                  inc ecx
15: eb f1               jmp _loop0
_break0:
17: 89 fe               mov esi,edi
19: 91                  xchg eax,ecx    ;ECX=0
_bsort:
1a: 60                  pusha
_cx2b:
1b: ac                  lodsb           ;Get the first char to compare
1c: 88 c2               mov dl,al       ;Save to DL
1e: c0 e8 05            shr al,5        ;Char class: [0-9]->1, [A-Z]->2, [a-z]->3
21: d7                  xlat            ;AL=EBX[AL] - priority for the char class 
22: 88 c6               mov dh,al       ;... goes to DH
24: 52                  push edx        ;First "comparable char" in DX goes to the stack
25: ac                  lodsb           ;Get the second char to compare
26: 88 c2               mov dl,al       ;\
28: c0 e8 05            shr al,5        ; > Same as the above
2b: d7                  xlat            ;/
2c: 88 c6               mov dh, al      ;Second "comparable char" in DX
2e: 58                  pop eax         ;The first one goes to AX
2f: 74 0e               jz _endpass     ;ZF is set by the last 'shr', and only on AL==0
31: 66 39 d0            cmp ax,dx       ;Upper halves of 32-bit regs may contain trash
34: 76 02               jbe _sorted
36: 92                  xchg eax,edx    ;Now AX<=DX
37: 41                  inc ecx         ;Swap counter
_sorted:
38: aa                  stosb           ;Store AL in-place
39: 92                  xchg eax,edx    ;AL=DL
3a: aa                  stosb           ;Store the second char
3b: 4e                  dec esi         ;Move pointers...
3c: 4f                  dec edi         ;...back one byte
3d: eb dc               jmp _cx2b       ;Repeat with the next two chars
_endpass:
3f: 85 c9               test ecx,ecx    ;Full pass completed, checking # of swaps made
41: 61                  popa            ;Restores ECX(0), ESI, EDI. Doesn't affect flags
42: 75 d6               jnz _bsort      ;If there were changes, repeat
_end:
44: 58                  pop eax         ;Deallocate EBX[]
45: c3                  ret
\$\endgroup\$
1
\$\begingroup\$

Emacs Lisp, 183 bytes

(lambda(s p)(let(l u n)(apply'concat(mapcar(lambda(l)(sort l'<))(dolist(e(string-to-list s)(mapcar(lambda(i)(nth i(list l u n)))p))(push e(cond((< ?` e)l)((< ?@ e)u)((< ?/ e)n))))))))

Slightly shorter than Java...

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

Clojure, 77 bytes

#(apply str(mapcat sort(map(group-by(fn[v](condp <(int v)90 0,57 1,2))%2)%)))

Not quite as short as the re-seq based one, and I couldn't figure out how to express that "(apply str(mapcat sort(map(...))))" in less space. group-by creates a hash-map which can be used as a function, when queried with an ingeger between 0 and 2 it returns the corresponding group, this orders the three different classes of characters.

This would be more compact than the re-seq solution if there were more character classes to handle as this only takes 5 extra characters / group like 57 1, instead of 8 for expression like #"[a-z]".

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

Python 2, 140 117 101 100 99 bytes

Everyone say, "Ewww!". At least it's readable... cough not really cough

lambda l,s:`sorted(s,key=lambda c:[[c<'a',c<'A'or'Z'<c,c>'9'][l[i]]for i in 0,1,2]+[ord(c)])`[2::5]

Try it online

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

R, 101 bytes

function(a,s,o=unlist(list(letters,LETTERS,0:9)[a]))cat(o[sort(match(strsplit(s,'')[[1]],o))],sep='')

Creates a vector with a-z, A-Z and 0-9 in given order and reorders characters of input string to match this ordering.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

J, 40 bytes

;@:{[:(<@/:~@}./.~2-64 96 I.3&u:)'aA0'&,
\$\endgroup\$
0
\$\begingroup\$

Java 8, 221 212 193 156 bytes

I should of course try to answer my own challenge as well. :) (And as usual in Java.)

a->i->{for(byte c[],j=0;j<3;System.out.print(new String(c)))java.util.Arrays.sort(c=i.replaceAll("[^a-z];[^A-Z];[^0-9]".split(";")[a[j++]],"").getBytes());}

-28 bytes saved thanks to @cliffroot.

Explanation:

Try it here.

a->i->{          // Method with integer-array and String parameters and no return-type
  for(byte c[],  //  Temp byte-array
      j=0;j<3;   //  Loop from 0 to 3 (exclusive)
      System.out.print(new String(c)))
                 //    After every iteration: print the byte-array as String
    java.util.Arrays.sort(
                 //   Sort the byte-array
      c=         //    After we've replaced the byte-array with
        i.replaceAll("[^a-z];[^A-Z];[^0-9]".split(";")[a[j++]],"").getBytes());}
                 //    all bytes of the uppercase letters, lowercase letters, or digits,
                 //    depending on the next number in the input-array
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You can replace your regexps with [^a-z] [^A-Z] [^0-9] and you can use getBytes() instead of toCharArray() \$\endgroup\$
    – cliffroot
    Commented Jul 13, 2016 at 14:14
  • \$\begingroup\$ @cliffroot Thanks. I'm pretty bad at regexes, but not using the ^ (not) was pretty dumb.. ;) \$\endgroup\$ Commented Jul 13, 2016 at 15:10
  • 1
    \$\begingroup\$ removes repetitive replaceAll calls String c(int[]a,String z){String r[]={"[^a-z]","[^A-Z]","[^0-9]"},o="";for(byte c[],i=0;i<3;){c=z.replaceAll(r[a[i++]],"").getBytes();java.util.Arrays.sort(c);o+=new String(c);}return o;} \$\endgroup\$
    – cliffroot
    Commented Jul 13, 2016 at 15:49

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