27
\$\begingroup\$

Challenge

Given a list of unique colour names as input, sort them in the order that they first appear in Joseph's Amazing Technicolour Dreamcoat.


Example

Input: green, blue, red, brown
Output: red, green, brown, blue

The full list of colours, in order, is:

 1. red
 2. yellow
 3. green
 4. brown
 5. scarlet
 6. black
 7. ochre
 8. peach
 9. ruby
10. olive
11. violet
12. fawn
13. lilac
14. gold
15. chocolate
16. mauve
17. cream
18. crimson
19. silver
20. rose
21. azure
22. lemon
23. russet
24. grey
25. purple
26. white
27. pink
28. orange
29. blue

Or as an array of strings:

["red","yellow","green","brown","scarlet","black","ochre","peach","ruby","olive","violet","fawn","lilac","gold","chocolate","mauve","cream","crimson","silver","rose","azure","lemon","russet","grey","purple","white","pink","orange","blue"]

Rules

  • You may take input by any reasonable, convenient means (e.g., an array of strings, a delimited string, individual strings) as long as it's permitted by our standard I/O rules, but please specify your input method in your answer.
  • You may do the same for your output.
  • The input will only ever contain colours from the above list.
  • Your solution should be able to handle empty inputs.
  • You may choose whether all words in the input are consistently uppercase, lowercase or title case but your output's casing must match your input's.
  • This is so lowest byte count in each language wins.
  • As always, standard loopholes are forbidden.

Test cases

Input: []
Output: []
Input: ["green", "blue", "red", "brown"]
Output: ["red", "green", "brown", "blue"]
Input: ["gold", "grey", "green"]
Output: ["green", "gold", "grey"]
Input: ["ruby","yellow","red","grey"]
Output: ["red", "yellow", "ruby", "grey"]
Input: ["gold", "green", "fawn", "white", "azure", "rose", "black", "purple", "orange", "silver", "ruby", "blue", "lilac", "crimson", "pink", "cream", "lemon", "russet", "grey", "olive", "violet", "mauve", "chocolate", "yellow", "peach", "brown", "ochre", "scarlet", "red"]
Output: ["red", "yellow", "green", "brown", "scarlet", "black", "ochre", "peach", "ruby", "olive", "violet", "fawn", "lilac", "gold", "chocolate", "mauve", "cream", "crimson", "silver", "rose", "azure", "lemon", "russet", "grey", "purple", "white", "pink", "orange", "blue"]
asked Dec 19, 2018 at 16:19
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Sandbox (hard to believe it'd been languishing there for 18 months!) \$\endgroup\$ Commented Dec 19, 2018 at 16:20

14 Answers 14

13
\$\begingroup\$

PowerShell, (削除) 262 (削除ここまで) (削除) 155 (削除ここまで) (削除) 151 (削除ここまで) (削除) 127 (削除ここまで) (削除) 125 (削除ここまで) 95 bytes

$args|sort{"rlyegwbrscbrocpyrvo lvnfaldgccvmacmcvseraolsrygpptwkpnoeb".indexof((-join$_[3,0]))}

Try it online!

(削除) Naive approach. (削除ここまで) PowerShell sort-object can sort based on a script block that gets executed for every object. Here we're simply getting the .IndexOf() the color from a string, which will assign a numerical value to each color, and then sorts based on those numbers. The string is constructed from the fourth and first letters of each color to ensure uniqueness. Output is implicit.

-4 bytes thanks to Shaggy.
-2 bytes thanks to mazzy.
A whopping -30 bytes thanks to KGlasier.

answered Dec 19, 2018 at 16:39
\$\endgroup\$
9
  • \$\begingroup\$ I don't know if you could do this efficiently (byte-wise), but if you sort by length 3 substrings and then sort with secondary key of the original string, the only collision is green grey which is in the right alphabetical order. \$\endgroup\$ Commented Dec 19, 2018 at 17:09
  • 2
    \$\begingroup\$ @Shaggy Yes, that works because .IndexOf() will return -1 if the string isn't found, which sorts red into the right ordering. Thanks! \$\endgroup\$ Commented Dec 19, 2018 at 17:13
  • \$\begingroup\$ i think you can remove brackets around a string. \$\endgroup\$ Commented Dec 19, 2018 at 18:22
  • 1
    \$\begingroup\$ Removed an r... rlyegwbrscbrocpyrvo lvnfaldgccvmacmcvseraolsrygpptwkpnoeb. Each color is indexed once, with exception of red, which matches 6 times. But one of the matches is the first, so it still works. I'd link a tio.run but the link is too long. \$\endgroup\$ Commented Dec 19, 2018 at 20:50
  • 1
    \$\begingroup\$ @KGlasier Wow, thanks for finding that string! That saves a lot of bytes. \$\endgroup\$ Commented Dec 20, 2018 at 13:37
10
\$\begingroup\$

JavaScript (SpiderMonkey), (削除) 104 (削除ここまで) 101 bytes

"When in doubt, just hash the bloody input."

a=>a.sort((a,b)=>(g=s=>'mgo0dakbrfs0h0000j9c412603e870500p0l0niq'[parseInt(s,36)%657%53%42])(a)>g(b))

Try it online!

answered Dec 19, 2018 at 17:14
\$\endgroup\$
2
  • \$\begingroup\$ I've seen (and been impressed by) hash-based solutions like this before. Is there an explanation anywhere for how the magic string/multiplier/mod values are generated? Is it just brute force until you find a set of values that gives a unique output for each of the possible color inputs, or is there a more clever approach? \$\endgroup\$ Commented Dec 19, 2018 at 19:03
  • 2
    \$\begingroup\$ @JackBrounstein This one was just a quick and dirty brute force search trying random values and minimizing only the maximum output (after the last modulo), without taking the length of the full chain into account (e.g. %99%55 is not better than %123%55 with this approach). So it's certainly sub-optimal. I may try something slightly more sophisticated later, though. \$\endgroup\$ Commented Dec 19, 2018 at 19:09
7
\$\begingroup\$

Jelly, 28 bytes

"1⁄2Ṗ©cƘʂẒẹMMỤẓHP’Œ?"ðÑþQ’,ḥμÞ

Try it online!

How it works

μ turns everything to its left into a monadic chain, which Þ maps over the input array and sorts the input according to the generated values.

"1⁄2Ṗ©cƘʂẒẹMMỤẓHP’ sets the return value to 176073885534954276199526358143331.

Œ? generates the 176073885534954276199526358143331th permutation of the positive integers (without the sorted tail), yielding \$\small[20,28,15,3,5,26,18,16,8,30,4,25,2,21,22,11,24,1,23,10,29,12,17,27,14,9,6,13,7,19]\$.

"ðÑþQ’ yields 391695582; , prepends it to the permutation. Then, c ompute Jelly's 391695582th hash function, mapping the resulting buckets to the integers of the permutation.

The magic constant 391695582 was found by Jelly's utils.

dennis-home:utils$ time ./findhash 30 29 <<< '["red","yellow","green","brown","scarlet","black","ochre","peach","ruby","olive","violet","fawn","lilac","gold","chocolate","mauve","cream","crimson","silver","rose","azure","lemon","russet","grey","purple","white","pink","orange","blue"]'
391695582
real 0m2.058s
user 0m15.077s
sys 0m0.023s
answered Dec 19, 2018 at 22:28
\$\endgroup\$
1
  • 2
    \$\begingroup\$ 353690280752 hashes the 29 colors in 29 buckets, but takes one more byte to encode. Using uppercase (332849952364) or titlecase (862442225888) also comes out at 28 bytes. \$\endgroup\$ Commented Dec 20, 2018 at 2:24
6
\$\begingroup\$

Python 3, 93 bytes

lambda r:sorted(r,key=lambda s:'iV^ZzwnFM@pYuOobXGAKyf[tUR]E'.find(chr(int(s,36)%127%60+64)))

Try it online!

Reads each color as a base-36 int. Brute-forced the moduli and chose an arbitrary offset among the 19 that didn't require escapes.

answered Dec 20, 2018 at 6:51
\$\endgroup\$
5
\$\begingroup\$

Powershell, (削除) 124 (削除ここまで) (削除) 120 (削除ここまで) (削除) 124 (削除ここまで) (削除) 119 (削除ここまで) (削除) 118 (削除ここまで) 102 bytes

$args|sort{$c=$_
'bluOrPiWPuG*yRusLeARoSiCriCrMCGoLFVOlRuPOBlSBGYR'-csplit'(?=[A-Z])'|%{$c-like"$_*"}}

Try It Online!

Explanation:

  1. The data string contains the first significant letters of the color labels in descending order. Except for the Grey label - G*y is shorter.

  2. -csplit'(?=[A-Z])' splits the data string to the array (blu,Or,Pi,W,Pu,G*y,Rus,Le,A,Ro,Si,Cri,Cr,M,C,Go,L,F,V,Ol,Ru,P,O,Bl,S,B,G,Y,R)

  3. |%{$c-like"$_*"} maps the string array to the array of boolean. Where True means "a color label starts from this string" (like is case-insensitive operator, csplit - case-sensitive. see doc).

  4. sort{} sorts a color lables by the arrays of boolean in ascending order.

The sorting by array is a very interesting feature in the Powershell. In this script all arrays have the same length and contain Boolean values only. This sorting is performed in the lexographic order of boolean arrays.

Therefore, the string can contain one-letter abbreviations for the last labels. If there is a match at the beginning of the array, the matches at the end have no effect.

 blu Or Pi W Pu G*y Rus Le A Ro Si Cri Cr M C Go L F V Ol Ru P O Bl S B G Y R
green: - - - - - - - - - - - - - - - - - - - - - - - - - - T - -
gold : - - - - - - - - - - - - - - - T - - - - - - - - - - T - -
grey : - - - - - T - - - - - - - - - - - - - - - - - - - - T - -
 : green < gold < grey

Where T is true and - is false.


Test script:

$f = {
$args|sort{$c=$_
'bluOrPiWPuG*yRusLeARoSiCriCrMCGoLFVOlRuPOBlSBGYR'-csplit'(?=[A-Z])'|%{$c-like"$_*"}}
}
@(
 ,( @(), @() )
 ,( ('green', 'blue', 'red', 'brown'), ('red', 'green', 'brown', 'blue') )
 ,( ("gold", "grey", "green"), ("green", "gold", "grey") )
 ,( ("ruby","yellow","red","grey"), ("red", "yellow", "ruby", "grey") )
 ,( ("gold", "green", "fawn", "white", "azure", "rose", "black", "purple", "orange", "silver", "ruby", "blue", "lilac", "crimson", "pink", "cream", "lemon", "russet", "grey", "olive", "violet", "mauve", "chocolate", "yellow", "peach", "brown", "ochre", "scarlet", "red"),
 ("red", "yellow", "green", "brown", "scarlet", "black", "ochre", "peach", "ruby", "olive", "violet", "fawn", "lilac", "gold", "chocolate", "mauve", "cream", "crimson", "silver", "rose", "azure", "lemon", "russet", "grey", "purple", "white", "pink", "orange", "blue") )
) | % {
 $inp,$expected = $_
 $result = &$f @inp # splatting
 "$("$result"-eq"$expected"): $result"
}

Output:

True:
True: red green brown blue
True: green gold grey
True: red yellow ruby grey
True: red yellow green brown scarlet black ochre peach ruby olive violet fawn lilac gold chocolate mauve cream crimson silver rose azure lemon
russet grey purple white pink orange blue
Shaggy
45k4 gold badges39 silver badges95 bronze badges
answered Dec 19, 2018 at 18:15
\$\endgroup\$
4
  • \$\begingroup\$ I have This site can’t be reached error. Sorry. \$\endgroup\$ Commented Dec 19, 2018 at 22:16
  • 1
    \$\begingroup\$ Added a revised TIO for you. \$\endgroup\$ Commented Dec 20, 2018 at 17:02
  • 1
    \$\begingroup\$ I've managed to get a new IP for TIO today. Is it still blocked for you? \$\endgroup\$ Commented Jan 8, 2019 at 20:06
  • \$\begingroup\$ It's Alive!!! Cool! And Thanks! \$\endgroup\$ Commented Jan 8, 2019 at 20:51
4
\$\begingroup\$

C (clang), (削除) 121 (削除ここまで) 119 bytes

#define j(i)index(".MH^>SALcD8Z!)3TF(RNe*aQU<,'",(**i^377)%75+30)
s(**a,**b){return j(a)-j(b);}f(*t,n){qsort(t,n,8,s);}

Try it online!

-2 bytes thanks ceilingcat!

answered Aug 12, 2021 at 15:42
\$\endgroup\$
0
3
\$\begingroup\$

I will improve the string compression in a while

Japt, (削除) 88 (削除ここまで) (削除) 78 (削除ここまで) 71 bytes

ñ@`䊐âwrÒ.cÖ ̈acru1⁄2ivo¤faØngoÒqauvœamsolv€osz ̈e¶s gœrpl–tpˆ„g1⁄2u`bXé4 ̄3

Try it online!

answered Dec 19, 2018 at 17:34
\$\endgroup\$
2
  • 1
    \$\begingroup\$ A quick port of one of the other solutions here comes in at 46 bytes, if you want to try for it. \$\endgroup\$ Commented Dec 20, 2018 at 13:34
  • \$\begingroup\$ @Shaggy I don't think they're trying for it anymore :P \$\endgroup\$ Commented Jan 13, 2019 at 1:08
3
\$\begingroup\$

Python 2, 186 bytes

lambda a:[y for x,y in sorted((max(" y gree br sc bla oc pe rub ol v f li go ch m cre cri si ro a le rus grey pu w pi or blu ".find(" %s "%c[:i+1])for i,j in enumerate(c)),c)for c in a)]

Try it online!

Finds all matches for progressive character substrings (Ex: "green" will check for "g", "gr", "gre", "gree", and "green") in the identifier string, and keeps the maximum index. "red" is always first, anf find() returns -1 for missing matches, so there is no identifier for red specifically.

Once the colors are turned into (index, color) pairs, sorts array on first item of pair and then discards first item of each pair.

answered Dec 19, 2018 at 21:44
\$\endgroup\$
3
\$\begingroup\$

Wolfram Language (削除) 255 213 (削除ここまで) 199 bytes

Fourteen bytes saved by Dennis, who avoided the " marks, using symbols instead of strings.

SortBy[#,{yellow,green,brown,scarlet,black,ochre,peach,ruby,olive,violet,fawn,lilac,gold,chocolate,mauve,cream,crimson,silver,rose,azure,lemon,russet,grey,purple,white,pink,orange,blue}~Position~#&]&

Try It Online!

answered Dec 19, 2018 at 17:10
\$\endgroup\$
0
2
\$\begingroup\$

Python 3, 130 bytes

lambda*a:sorted(a,key=lambda c:("r,ylgebwsrtbcorpcryovvlfnlagdccamvca cmnsvrearlorsgyppwtpkonbe".find(c[::3]+" "*(c=="cream")),c))

Try it online!

answered Dec 19, 2018 at 17:02
\$\endgroup\$
5
  • \$\begingroup\$ @Shaggy I don't think so? can you give me an input and the intended output \$\endgroup\$ Commented Dec 19, 2018 at 17:19
  • \$\begingroup\$ @AdmBorkBork Thanks, just realized what Shaggy meant by that. I was only comparing green and grey to each other lol \$\endgroup\$ Commented Dec 19, 2018 at 17:21
  • \$\begingroup\$ To add to Shaggy and AdmBorkBork's comments, "green" and "grey" both begin with "gre". \$\endgroup\$ Commented Dec 19, 2018 at 17:21
  • \$\begingroup\$ @Shaggy fixed i think \$\endgroup\$ Commented Dec 19, 2018 at 17:23
  • 1
    \$\begingroup\$ @Shaggy Fixed it, thanks. Required a bit of a hack for cream since ca is a substring of cca for chocolate oof. \$\endgroup\$ Commented Dec 21, 2018 at 15:48
2
\$\begingroup\$

C# (Visual C# Interactive Compiler), (削除) 321 (削除ここまで) (削除) 219 (削除ここまで) (削除) 210 (削除ここまで) (削除) 161 (削除ここまで) (削除) 159 (削除ここまで) 138 bytes

n=>n.OrderBy(a=>a!="grey"?"yelgrebroscablaochperuboliviofawlilgolchomaucrecrisilrosazulemruspurwhipinorablu".IndexOf(a.Substring(0,3)):65)

Try it online!

-3 bytes thanks to Shaggy, -18 thanks to TheLethalCoder

Takes input as a List<string>, returns an IOrderedEnumerable<string>

How this works is that it orders the list by each string's index in the original string. The original string has every color except for grey turned to it's first three letters. Grey is not there, since green and grey would cause ambiguity. Red isn't there either, since IndexOf returns -1 if the string doesn't appear.

Shorter version taking IOrderedEnumerable as input, 137 bytes

n=>n.ThenBy(a=>a!="grey"?"yelgrebroscablaochperuboliviofawlilgolchomaucrecrisilrosazulemruspurwhipinorablu".IndexOf(a.Substring(0,3)):65)

Takes advantage of the fact that ThenBy is 1 byte shorter than OrderBy, but ThenBy only operates on IOrderedEnumerables though.

Try it online!

answered Dec 19, 2018 at 19:48
\$\endgroup\$
5
  • \$\begingroup\$ I think you can remove red from your lookup string and replace 68 with 65 to save 3 bytes. On my phone so haven't fully tested it. \$\endgroup\$ Commented Dec 20, 2018 at 8:16
  • \$\begingroup\$ You can use the string inline with an implicit return for 142 bytes n=>n.OrderBy(a=>a!="grey"?"redyelgrebroscablaochperuboliviofawlilgolchomaucrecrisilrosazulemruspurwhipinorablu".IndexOf(a.Substring(0,3)):68); However, you need to include the usings in your byte count as they are required to run. You can use the namespace trick to shorten the count required though. \$\endgroup\$ Commented Dec 20, 2018 at 11:51
  • \$\begingroup\$ If I use the namespace trick, do I have to add the namespace to my number of bytes? \$\endgroup\$ Commented Dec 20, 2018 at 16:34
  • \$\begingroup\$ I can just change the compiler to Visual C# Interactive Compiler, and then I won't have to add the usings \$\endgroup\$ Commented Dec 20, 2018 at 16:44
  • \$\begingroup\$ Ah good idea on changing to Interactive but yes if you did the namespace trick you'd have to include it in your byte count. Essentially adding namespace System.Linq{} or whatever you would have chosen. \$\endgroup\$ Commented Dec 20, 2018 at 17:13
2
\$\begingroup\$

Charcoal, (削除) 69 (削除ここまで) (削除) 68 (削除ここまで) (削除) 63 (削除ここまで) (削除) 56 (削除ここまで) 52 bytes

F⪪"&⌊Oτe¿k⟲iζLbψ#>φuCNoς...X◧9gF→G⌈H≡M*e{-"2Φθ=ι+§κ0§κ3

Try it online! Link is to verbose version of code. Explanation: Now a port of @Sok's Pyth answer.

F⪪"&⌊Oτe¿k⟲iζLbψ#>φuCNoς...X◧9gF→G⌈H≡M*e{-"2

Take the compressed string rrylgebwsrbcorpcryovvlfnlagdccmvcacmsvrearlorsgyppwtpkonbe and loop over each substring of length 2.

Φθ=ι+§κ0§κ3

For each substring print those input strings whose first and fourth (cyclically) characters equal the substring.

answered Dec 19, 2018 at 18:37
\$\endgroup\$
3
  • \$\begingroup\$ Would it help to take inputs in Title case? Then Li would be a unique substring for Lilac and you wouldn't need the 99 hack. I don't know if including uppercase letters would make the compressed string longer, though. \$\endgroup\$ Commented Aug 13, 2021 at 2:35
  • \$\begingroup\$ @DLosc It would make the compressed string longer, but overall the saving would be 2 bytes. \$\endgroup\$ Commented Aug 13, 2021 at 8:00
  • \$\begingroup\$ @DLosc Which turns out to be not as good as simply porting a later answer, unfortunately. \$\endgroup\$ Commented Aug 13, 2021 at 9:07
1
\$\begingroup\$

Pyth, 66 bytes

oxc."ayÇæ£ðÐ\~@iF[2BÍÐ:Yë)^ksTTã"2s@LN,03

Try it online here, or verify all the test cases at once here.

The colours in the list can be uniquely identified by taking the characters at index 0 and 3, assuming modular indexing. This results in the following mapping:

rr -> red
yl -> yellow
ge -> green
bw -> brown
sr -> scarlet
bc -> black
or -> ochre
pc -> peach
ry -> ruby
ov -> olive
vl -> violet
fn -> fawn
la -> lilac
gd -> gold
cc -> chocolate
mv -> mauve
ca -> cream
cm -> crimson
sv -> silver
re -> rose
ar -> azure
lo -> lemon
rs -> russet
gy -> grey
pp -> purple
wt -> white
pk -> pink
on -> orange
be -> blue

Full explanation:

oxc."..."2s@LN,03Q Implicit: Q=eval(input())
 Trailing Q inferred, dictionary string replaced with ... for brevity
o Q Order the elements of Q, as N, using:
 ,03 [0,3]
 @LN Get the characters at the above indices in N
 s Concatenate into a string
 The above is result {1}
 ."..." The compressed dictionary string
 c 2 Split into chunks of length 2
 x Get the index of {1} in the above
 Implicit print of sorted list
answered Dec 20, 2018 at 10:46
\$\endgroup\$
1
\$\begingroup\$

05AB1E, 48 bytes

Σ.•Aå2мÕh∊þèmvƶ\kΛ1YŠíJ>J#θ12©,ドルÙ{η¦ù-•2ôy¬s3è«k

Same solution as most other answers. Will try to golf it down from here later.

Try it online or verify all test cases.

Explanation:

Σ # Sort the (implicit) input-list by:
 .•Aå2мÕh∊þèmvƶ\kΛ1YŠíJ>J#θ12©,ドルÙ{η¦ù-•
 # Push compressed string "rrylgebwsrbcorpcryovvlfnlagdccmvcacmsvrearlorsgyppwtpkonbe"
 2ô # Split into parts of size 2
 y # Push the current string of the list we're sorting
 ¬ # Push its head (without popping)
 s # Swap so the string is at the top of the stack again
 3è # Get the character at index 3 (with automatic wraparound)
 « # Merge both characters together
 k # And get the index in the compressed string to sort on

See this 05AB1E tip (section How to compress strings not part of the dictionary?) to understand how .•Aå2мÕh∊þèmvƶ\kΛ1YŠíJ>J#θ12©,ドルÙ{η¦ù-• is "rrylgebwsrbcorpcryovvlfnlagdccmvcacmsvrearlorsgyppwtpkonbe".

answered Dec 21, 2018 at 8:52
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.