# 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. – Magic Octopus Urn Jan 10 '17 at 21:40
• Can we output a list of characters instead of a string? – Wheat Wizard Jan 10 '17 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". – Stewie Griffin Jan 10 '17 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. – Stewie Griffin Jan 10 '17 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? – George Reith Jan 11 '17 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 – shabunc Jan 12 '17 at 1:36
• @shabunc If you want to see the new J, check out github.com/DennisMitchell/jelly – isaacg Jan 12 '17 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 – geisterfurz007 Jan 12 '17 at 11:29
• As I said, almost made for Jelly. :) – Dennis Jan 12 '17 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. – FlipTack Jan 10 '17 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. – Wheat Wizard Jan 10 '17 at 22:05
• You can make f a string instead of a list to save a few bytes. – flornquake Jan 11 '17 at 3:08
• If you take a=list(input()), you can do a.remove(c), which is a net savings. – xnor Jan 11 '17 at 3:43
• Switching to Python 3 would save a lot of bytes. tio.run/nexus/… – Dennis Jan 11 '17 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. # Python 2, 75 bytes lambda s:zip(*sorted((s[:i].count(c),c)for i,c in enumerate(s)))[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 '17 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] – Wheat Wizard Jan 11 '17 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! – Dennis Jan 11 '17 at 4:45 • @WheatWizard Good eye. Thanks! – Dennis Jan 11 '17 at 4:45 • This fails if the string has backslashes in it. – Lynn Jan 12 '17 at 3:02 # Dyalog APL, 21 chars = 39 bytes t[0~⍨∊⍉(⊢⌸t)[⍋∪t←⍞;]]  t[...] index t (to be defined shortly) with... 0~⍨ zeros removed from ∊ the enlisted (flattened) ⍉ transposed (⊢⌸t)[...;] keyed* t, row-indexed by... ⍋ the indices which would sort ∪ the unique letters of t←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 '17 at 6:39 • @wptreanor ⌸ causes the entire thing to be UTF-8 instead of one byte per char. – Adám Jan 11 '17 at 7:16 # 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? – Stewie Griffin Jan 10 '17 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 ;-) – cleblanc Jan 10 '17 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? – Stewie Griffin Jan 10 '17 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 – JungHwan Min Jan 10 '17 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. – Stewie Griffin Jan 10 '17 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. – JungHwan Min Jan 10 '17 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. – ngenisis Jan 11 '17 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 '17 at 3:33 • I really like this method, sorting with a function that mutates. The nesting of tuples is clever too. – xnor Jan 11 '17 at 4:10 • @xnor Thanks, fixed. – flornquake Jan 11 '17 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 +/@(={:) – miles Jan 12 '17 at 9:15 • @Miles Oh yeah, because a train has infinite rank. Nice, thanks! – Zgarb Jan 12 '17 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). – JungHwan Min Jan 13 '17 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). – JungHwan Min Jan 13 '17 at 1:56 • @JungHwanMin fixed to RuleDelayed. thanks. – spacemit Jan 17 '17 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);$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);$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 – James Jan 12 '17 at 15:40 # 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 '17 at 14:25
• {[~] flat roundrobin |.comb.classify(~*){*}.sort»[*]} -- This variation is only 54 bytes. – smls Jan 11 '17 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 '17 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 '17 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 '17 at 9:34
• @Neil Awesome thanks -2 bytes – George Reith Jan 11 '17 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}
`