# Sort a string, sort of

If you sort a string you'll typically get something like:

         ':Iaaceeefggghiiiiklllllmnnooooprrssstttttuuyyyy


Yes, that was the first sentence sorted.

As you can see, there are a lot of repeated characters, aa, eee, ttttt, 9 spaces and so on.

If we add 128 to the ASCII-value of the first duplicate, 256 to the second, 384 to the third and so on, sort it again and output the new string (modulus 128 to get the same characters back) we get the string:

 ':Iacefghiklmnoprstuy aegilnorstuy egilosty iloty lt


(Note the single leading space and the 4 trailing spaces).

The string is "sequentially sorted" <space>':I....uy, <space>aeg....uy, <space>egi....ty, <space>iloty, <space>lt, <space>, <space>,<space>, <space>.

It might be easier to visualize this if we use a string with digits in it. The string 111222334 will when "sorted" be: 123412312.

## Challenge:

To no surprise, the challenge is to write a code that sorts a string according to the description above.

You can assume that the input string will contain only printable ASCII-characters in the range 32-126 (space to tilde).

Test cases:

**Test cases:**
*:Tacest*es*s*

If you sort a string you'll typically get something like:
':Iacefghiklmnoprstuy aegilnorstuy egilosty iloty lt

Hello, World!
!,HWdelorlol

#MATLAB, 114 bytes
#,14ABLMTbesty 1A

f=@(s)[mod(sort(cell2mat(cellfun(@(c)c+128*(0:nnz(c)-1),mat2cell(sort(s),1,histc(s,unique(s))),'un',0))),128),''];
'()*+,-0128:;=@[]acdefhilmnoqrstuz'(),0128@acefilmnorstu'(),12celmnostu'(),12celnstu(),clnst(),cls(),cs(),()()()()


This is , so the shortest code in each language counted in bytes will winref.

• Title is a bit confusing, resulting in me thinking this and ignoring the description: tio.run/nexus/05ab1e#@1@td2jh4ZVe//… Nice challenge otherwise, I'll work on expanding that to meet the brief. Jan 10, 2017 at 21:40
• Can we output a list of characters instead of a string? Jan 10, 2017 at 21:52
• If you can input a string, then the output should be a string too. If a list of characters is the normal way of inputting and outputting strings in your languages then it's OK. You can for instance not output {'S', 'g', 'i', 'n', 'r', 't'} in Python, since the "normal" way to do it is "String". Jan 10, 2017 at 21:54
• I'll correct my comment above: a string is a list of characters, so a list of characters is accepted output. However, a list of strings is not accepted. This means, if it's possible to add a second character to an element in your list then it's not accepted. As an example: {'a','b'} is not accepted in Matlab since you can add a character to each of the characters like this: {'aa','b'}. Your input and output must be on the same format. Jan 10, 2017 at 23:40
• @StewieGriffin When you say sorted according to the description above. Do you mean my sort algorithm must follow the process of modifying ASCII values or it just has to produce the same output as that algorithm? Jan 11, 2017 at 0:01

# Pyth, 5 bytes

s.T.g


Test suite

Very straightforward: Group and sort, transpose, concatenate.

s.T.g
s.T.gkQ    Implicit variables
.gkQ    Group the input input lists of elements whose values match when the
identity function is applied, sorted by the output value.
.T        Transpose, skipping empty values. This puts all first characters into
a list, then all second, etc.
s          Concatenate.

• Pyth has everything to become new J, it's awesome Jan 12, 2017 at 1:36
• @shabunc If you want to see the new J, check out github.com/DennisMitchell/jelly Jan 12, 2017 at 4:51

# Jelly, 3 bytes

ĠZị


Try it online!

### How it works

Oh boy, this challenge was all but made for Jelly.

The group atom (Ġ) takes an array1 as input and groups indices that correspond to identical elements of the array. The array of index groups is sorted with the corresponding elements as keys, which is precisely the order we require for this challenge.

Next, the zip atom (Z) transposes rows and columns of the generated (ragged) matrix of indices. This simply consists of reading the columns of the matrix, skipping elements that are not present in that column. As a result, we get the first index of the character with the lowest code point, followed by the first index of the character with the second lowest code point, … followed by the second index of the character with the lowest code point, etc.

Finally, the unindex atom (ị) retrieves the elements of the input array at all of its indices in the generated order. The result is a 2D character array, which Jelly flattens before printing it.

1 Jelly doesn't have a string type, just arrays of characters.

• "Oh boy, this challenge was all but made for Jelly." -> 3 byte answer Jan 12, 2017 at 11:29
• As I said, almost made for Jelly. :) Jan 12, 2017 at 12:54

# Python 3, 109105104103999390888179 69 bytes

2 bytes saved thanks to FlipTack

7 bytes saved because flornquake caught my dumb error

2 bytes saved thanks to xnor

10 bytes saved thanks to Dennis

a=[*input()]
while a:
for c in sorted({*a}):print(end=c);a.remove(c)


## Explanation

We start by converting our string to a list using a splat and storing that list in a variable a. Then while our a is not the empty list we go through each unique member of a in sorted order, print it and remove a copy of that character from the list.

Each iteration prints thus prints one copy of each character present in a.

• @StewieGriffin set is an unsorted set. Jan 10, 2017 at 22:03
• @StewieGriffin when printed they are sorted but not by their ASCII values exactly. It often appears they are but I believe they are sorted by some type of hash. Jan 10, 2017 at 22:05
• You can make f a string instead of a list to save a few bytes. Jan 11, 2017 at 3:08
• If you take a=list(input()), you can do a.remove(c), which is a net savings.
– xnor
Jan 11, 2017 at 3:43
• Switching to Python 3 would save a lot of bytes. tio.run/nexus/… Jan 11, 2017 at 4:12

import Data.List
concat.transpose.group.sort


Usage example:

Prelude Data.List> concat.transpose.group.sort $"If you sort a string you'll typically get something like:" " ':Iacefghiklmnoprstuy aegilnorstuy egilosty iloty lt "  Sort, group equal chars to a list of strings (e.g. "aabbc" -> ["aa","bb","c"]), transpose and flatten into a single string, again. • This might be stupid thing to ask but how does this adds 128,256,384.... to the repeated values? Jan 19 at 5:44 # Python 2, 75 bytes lambda s:zip(*sorted((s[:i].count(c),c)for i,c in enumerate(s)))[1][2::5]  Try it online! • Don't know if it's valid but lambda s:[sorted((1e9+s[:i].count(c),c)for i,c in enumerate(s))][18::21] works for strings with max length 9e9. – xnor Jan 11, 2017 at 4:22 • @xnor you can drop the [] and change 18 to 17 to save two bytes. lambda s:sorted((1e9+s[:i].count(c),c)for i,c in enumerate(s))[17::21] Jan 11, 2017 at 4:38 • @xnor At the very least, this should be a valid 32-bit Python golf. I tried to get rid off the zip, but I don't think adding 1e9 would have ever occurred to me... Thanks! Jan 11, 2017 at 4:45 • @WheatWizard Good eye. Thanks! Jan 11, 2017 at 4:45 • This fails if the string has backslashes in it. – Lynn Jan 12, 2017 at 3:02 # APL (Dyalog Unicode), 21 20 bytes t[0~⍨∊⍉(⊂⍋∪t)⌷⊢⌸t←⍞]  Try it online! t[...] index t (to be defined shortly) with... 0~⍨ zeros removed from ∊ the enlisted (flattened) ⍉ transposed (⊂)⌷ reordered using… ⍋ the indices which would sort ∪ the unique letters of tt (to be defined shortly) ⊢⌸t keyed* t, which has the value of ⍞ prompted text input TryAPL online! ⊢⌸t creates a table where the rows (padded with zeros for a rectangular table) list each unique letters' indices in t. • which of the glyphs are more expensive? – ren Jan 11, 2017 at 6:39 • @ren Updated to use new technology that allows counting each glyph as a single byte. – Adám Jan 19 at 8:43 # C, 109106105104102100979896 91 Bytes Back up to 98 Bytes, needed to initialize j to make f(n) re-useable Down to 96 Bytes using puts in place of strlen B-) It's strange I had to back to strlen but I got rid of the for(;i++;) loop so now it's down to 91 Bytes. Apparently the man page for puts reads; "RETURNS If successful, the result is a nonnegative integer; otherwise, the result is EOF'."  ... I was lucky it was working in the first place char*c,i,j;f(m){for(j=strlen(m);j;++i)for(c=m;*c;c++)if(*c==i){*c=7,putchar(i),j--;break;}}  test code... main(c,v)char**v; { char test[] = "If you sort a string you'll typically get something like: "; char test2[] = "Hello, World!"; f(test);puts(""); f(test2);puts(""); }  Here are a few test cases, now it's time to golf this down C:\eng\golf>a.exe ':Iacefghiklmnoprstuy aegilnorstuy egilosty iloty lt !,HWdelorlo  • Are the trailing spaces left out in the first test case? Jan 10, 2017 at 22:07 • I have three trailing spaces in the first test case... That's because I didn't include the trailing space on the input string ;-) Jan 10, 2017 at 22:10 # Mathematica, 6860 59 bytes Split[Characters@#~SortBy~ToCharacterCode]~Flatten~{2}<>""&  Accepts a String. Outputs a String. If list of characters were allowed (46 bytes): Split[#~SortBy~ToCharacterCode]~Flatten~{2,1}&  Version using Sort (40 bytes): Split@Sort@Characters@#~Flatten~{2}<>""&  This version cannot be my answer because Sort cannot be used here; Sort sorts by canonical order, not by character code. • I don't know mathematica so this might be just fine, but did you read this comment? Jan 10, 2017 at 23:22 • @StewieGriffin Welp, nope. I can fix that, but doesn't that give an unfair advantage to languages that don't have a String vs Char[] distinction? Related meta discussion Jan 10, 2017 at 23:29 • Good point. I made a correction, see the comment below the original. Fair? I'm not sure if this makes your answer valid or not. Jan 10, 2017 at 23:42 • @StewieGriffin Mathematica doesn't have a distinction between characters and strings. Even the Characters command technically output a list of length-1 strings. Jan 10, 2017 at 23:58 • @StewieGriffin I think this is also relevant. I think it's better to allow the input in any reasonable format, be it a string, list of length 1 strings, array of characters, array of bytes, etc. Jan 11, 2017 at 1:47 # Python 2, 77 76 bytes d={} def f(c):d[c]=r=d.get(c,c),;return r printsorted(input(),key=f)[2::5]  Takes a quoted string as input from stdin. Try it online! • I think this isn't allowed because functions have to be re-usable. You could make it a program. – xnor Jan 11, 2017 at 3:33 • I really like this method, sorting with a function that mutates. The nesting of tuples is clever too. – xnor Jan 11, 2017 at 4:10 • @xnor Thanks, fixed. Jan 11, 2017 at 9:20 ## JavaScript (ES6), 79 bytes f=s=>s&&(a=[...new Set(s)]).sort().join+f(a.reduce((s,e)=>s.replace(e,),s)) <input oninput=o.textContent=f(this.value)><pre id=o> Works by extracting the set of unique characters, sorting it, removing them from the original string, and recursively calculating the sort of the rest of the string. 81 byte solution that I found interesting: f=s=>s&&(s=[...s].sort().join).replace(r=/(.)(\1*)/g,"$1")+f(s.replace(r,"$2"))  ## J, 16 15 bytes /:+/@(={:)\;"0]  This is a verb that takes and returns one string. Try it online! Miles saved a byte, thanks! ## Explanation Nothing too fancy here: sort primarily by order of occurrence, secondarily by char value. /:+/@(={:)\;"0] Input is y. \ Map over prefixes: +/ Sum @( ) of = bit-array of equality {: with last element. This gives an array of integers whose i'th element is k if index i is the k'th occurrence of y[i]. ; Pair this array "0 element-wise ] with y /: and sort y using it as key.  • I think you can save a byte moving summation to the outside of the parentheses +/@(={:) Jan 12, 2017 at 9:15 • @Miles Oh yeah, because a train has infinite rank. Nice, thanks! Jan 12, 2017 at 9:19 # Mathematica, 55 bytes, non-competing (Sort@Characters@#//.{a___,b_,b_,c___}:>{a,b,c,b})<>""&  Edit: Unfortunately, Mathematica's sort is not by character codes, but by alphabetical order, where uppercase immediatly follows lowercase (ie Hi There is sorted to { , e, e, h, H, i, r, T}). This works using patterns: //.{a___,b_,b_,c___}:>{a,b,c,b} a___ c___ (Three _) a zero or more members, named a and c b_,b_ exactly one member, repeated twice (since they have the same name) :> Delayed Rule (replace left hand side with right hand side.) Delayed Rule evaluate on each substitution, avoiding conflicts with predefined variables {a,b,c,b} put one of the b-named member after all other sequences //. repeat until no change (aka Replace Repeated)  • One minor thing: Rule (->) should be RuleDelayed (:>) (no change in byte count) because both sides of Rule has variables. Rule can cause conflicts with pre-existing definitions. For instance: a=3;5/.{a_->a} returns 3, not 5. (a_->a evaluates to a_->3 -- if you use a_:>a, it stays that way and a=3;5/.{a_:>a} returns 5). Jan 13, 2017 at 1:33 • I marked your answer non-competing because it does not do what the question specifies (sort by character code, not in canonical order). Jan 13, 2017 at 1:56 • @JungHwanMin fixed to RuleDelayed. thanks. Jan 17, 2017 at 8:17 # Brainf*ck, 458 226 bytes ,[>>>>>>,]<<<<<<[[-<<<+<<<]>>>[>>>[>>>>>>]<<<[>>--[<->--]<-<[>->+<[>]>[<+>-]<<[<]>-]>>.[[-]<]<<<[[>>>>>>+<<<<<<-]<<<]>>>>>>]>>>[>>>[>>>>>>]<<<[>>--[<->--]<-<[>->+<[>]>[<+>-]<<[<]>-]>>[-<+<+>>]<[->>+<<]<[<<<<<<]>>>]>>>]]<<<<<<]  Try it online! - BF # Numberwang, 262 226 bytes 8400000087111111442111911170004000400000071114002241202271214020914070419027114170270034427171114400000091111112711170000007000400040000007111400224120227121402091407041902711417027004219190071420091171411111170007000771111117  Try it online! - NW I put both of these here because they are identical code. # PHP, 83 bytes for($s=count_chars($argv[1]);$s=array_filter($s);$c%=128)echo$s[++$c]--?chr($c):'';  Unfortunately you can't have unset in a ternary so I need to use the annoyingly long array_filter. Use like: php -r "for($s=count_chars($argv[1]);$s=array_filter($s);$c%=128)echo$s[++$c]--?chr($c):'';" "If you sort a string you'll typically get something like:"  ## Python 2, 70 bytes f=lambda s,i=0,c='':s[i>>7:]and(s.count(c)>i>>7)*c+f(s,i+1,chr(i%128))  Try it online This is very inefficient. The test link changes the i>>7 to i>>5 and sets the recursion limit to 10000. Assumes the inputs only has ASCII values up to 126. Uses the div-mod trick to iterate through two loops: minimum counts i/128 in the outer loop and ASCII values i%128 in the inner loop. Includes a character c with the given ASCII value if the number of times it appears in the string is at least its minimum count. The code uses a trick to simulate the assignment c=chr(i%128) so that it can be referenced in the expression (s.count(c)>i>>7)*c. Python lambdas do not allow assignment because they only take expressions. Converting to a def or full program is still a net loss here. Instead, the function pushes forward the value chr(i%128) to the next recursive call as an optional input. This is off by one because i has been incremented, but doesn't matter as long as the string doesn't contain special character '\x7f' (we could also raise 128 to 256). The initial c='' is harmless. # V, 37 36 bytes Thanks @DJMcMayhem for the byte! Í./&ò dd:sor Íî òÍ¨.©¨±«©±À!¨.«©/±³²  Try it online! Not sure I like the regex at the end, but I needed to make the ò break somehow. ### Explain Í./&ò #All chars on their own line dd:sor #Delete empty line, sort chars Íî #Join all lines together s/\n// òÍ¨.©¨±«©±À!¨.«©/±³² #until breaking s/\v(.)(\1+)\1@!(.+)/\3\2\1  • Íî (or :%s/\n//g) is shorter than VGgJ Jan 12, 2017 at 15:40 # Vyxald, 3 bytes sĠ∩  Try it Online! s # Sort Ġ # Group run lengths ∩ # Transpose # (d flag) take deep sum  # Perl 6, 68 bytes {my \a=.comb.sort;[~] flat roundrobin |a.squish.map({grep *eq$_,a})}


I was a little surprised to find that there's no built-in way to group like elements in a list. That's what the squish-map bit does.

• I get "This Seq has already been iterated" unless I rename a to @a (+2 bytes). Also, grep *eq$_, can be written grep$_, (-3 bytes) since a string is a valid smart-matcher.
– smls
Jan 11, 2017 at 14:25
• {[~] flat roundrobin |.comb.classify(~*){*}.sort»[*]} -- This variation is only 54 bytes.
– smls
Jan 11, 2017 at 14:45
• @smis I don't see that error. Maybe we're using different versions? I'm on rakudo-star-2016.10. Anyway, your solution puts mine to shame, you should post it as a separate answer.
– Sean
Jan 11, 2017 at 17:33
• I'm using a bleeding-edge Rakudo compiled from the main branch of the git repo this week. Anyway, I posted the classify-based solution as a separate answer now.
– smls
Jan 11, 2017 at 18:43

# JavaScript (ES6), 77 75 bytes

s=>(a=[],x={},[...s].sort().map(c=>a[x[c]=n=-~x[c]]=(a[n]||'')+c),a).join


Stable sorts the lexicographically sorted string by nth occurence

F=s=>(a=[],x={},[...s].sort().map(c=>a[x[c]=n=-~x[c]]=(a[n]||'')+c),a).join

const update = () => {
console.clear();
console.log(F(input.value));
};
input.oninput = update;
update();
#input {
width: 100%;
box-sizing: border-box;
}
<input id="input" type="text" value="         ':Iaaceeefggghiiiiklllllmnnooooprrssstttttuuyyyy" length=99/>
<div id="output"></div>

• 1+~~ is the same as -~.
– Neil
Jan 11, 2017 at 9:34
• @Neil Awesome thanks -2 bytes Jan 11, 2017 at 11:49

# Perl 6, 54 bytes

{[~] flat roundrobin |.comb.classify(~*){*}.sort»[*]}


Explanation:

• { }: A lambda that takes one argument -- e.g. 21211.
• .comb: Split the input argument into a list of characters -- e.g. (2,1,2,1,1).
• .classify(~*): Group the characters using string comparison as the grouping condition, returning an unordered Hash -- e.g. { 2=>[2,2], 1=>[1,1,1] }.
• {*}: Return a list of all values of the Hash -- e.g. [2,2], [1,1,1].
• .sort: Sort it -- e.g. [1,1,1], [2,2].
• »[*]: Strip the item containers the arrays were wrapped in due to being in the hash, so that they won't be considered as a single item in the following step -- e.g. (1,1,1), (2,2).
• roundrobin |: Zip the sub-lists until all are exhausted -- e.g. (1,2), (1,2), (1).
• flat: Flatten the result -- e.g. 1, 2, 1, 2, 1.
• [~]: Concatenate it to get a string again -- e.g. 12121.

(Credit for the roundrobin approach goes to Sean's answer.)

# 05AB1E, 15 bytes

{.¡"ä"©¹g×«øJ®K


Try it online! or as a Test suite

Explanation

{                # sort input
.¡              # group by equal elements
"ä"©          # push "ä" and store a copy in the register
¹g×       # repeat the "ä" input-nr times
«      # concatenate the result to each string in the grouped input
ø     # zip
J    # join to string
®K  # remove all instances of "ä" in the string


10 of the 15 bytes are for getting around 05AB1E's way of handling zipping strings of different length.

# FSharp, 194190170140 133 bytes

let f=Seq.map
let(@)=(>>)
f int@Seq.groupBy id@f(snd@Seq.mapi((*)128@(+)))@Seq.concat@Seq.sort@f((%)@(|>)128@byte)@Array.ofSeq@f char


Using Seq instead of Array saves a couple of bytes

Defining a shorter name, and using another maps to avoid a (fun ->) block

It turns out F# can map a char to an in, so removing the shortened name of System.Text.Encoding.ASCII, and adding in another map saves me 20 bytes!

Returning a char array instead of a string, saves me 30 bytes!

I no longer need to make sure it's a string, saves me 7 bytes

# Husk, 4 bytes

ΣTgO


Try it online!

## Explanation

ΣTgO
O Order
g  group
T   Transpose
Σ    join


# JavaScript (ES6), 114 bytes

Separated with newline for clarity, not part of byte count:

s=>[...s].map(a=>(m[a]=-~m[a])*128+a.charCodeAt(),m={})
.sort((a,b)=>a-b).map(a=>String.fromCharCode(a%128)).join


## Demo

**Test cases:**
*:Tacest*es*s*

If you sort a string you'll typically get something like:
':Iacefghiklmnoprstuy aegilnorstuy egilosty iloty lt

Hello, World!
!,HWdelorlol

#MATLAB, 114 bytes
#,14ABLMTbesty 1A

f=@(s)[mod(sort(cell2mat(cellfun(@(c)c+128*(0:nnz(c)-1),mat2cell(sort(s),1,histc(s,unique(s))),'un',0))),128),''];
$#2  Try it online! # Ruby, 59+1 = 60 bytes Adds one byte for the -n flag. Port of @PatrickRoberts' dictionary solution. d={};print *$_.chars.sort_by{|c|d[c]||=0;c.ord+128*d[c]+=1}


# BQN, 6 bytesSBCS

∾·⊒⊸⊔∧
`

Run online!

sort, group by occurrence count, join.