According to RollingStone, below are the 26 greatest singers of all time:

Aretha Franklin         Al Green
Ray Charles             Robert Plant
Elvis Presley           Mick Jagger
Sam Cooke               Tina Turner
John Lennon             Freddie Mercury
Marvin Gaye             Bob Marley
Bob Dylan               Smokey Robinson
Otis Redding            Johnny Cash
Stevie Wonder           Etta James
James Brown             David Bowie
Paul McCartney          Van Morrison
Little Richard          Michael Jackson
Roy Orbison             Jackie Wilson

You can get this as a list of strings here.


Given a singer name, print or return a letter from A to Z which uniquely identifies this singer. (If your code returns A for Bob Dylan, then it cannot return A for any other singer.)

As opposed to other similar challenges, the mapping is up to you as long as it's collision-free.


  • The input is guaranteed to be one of the 26 singer names listed above with this exact spelling and without any leading or trailing whitespace.
  • You may output the letter in either lowercase or uppercase. But it must be consistent.
  • You are encouraged to provide a test suite for all 26 possible inputs.
  • This is , so the shortest answer in bytes wins!
  • \$\begingroup\$ (Deleted sandbox entry.) \$\endgroup\$
    – Arnauld
    Commented Oct 10, 2017 at 7:24
  • 19
    \$\begingroup\$ Dear Rolling Stone: Bob Dylan is truly one of the greatest musicians ever. But a great singer? \$\endgroup\$
    – Luis Mendo
    Commented Oct 10, 2017 at 10:45
  • \$\begingroup\$ @LuisMendo I'm a bit salty about a few of these choices as well (cough cough where's Steve Tyler cough) \$\endgroup\$ Commented Oct 10, 2017 at 16:07
  • \$\begingroup\$ @LordFarquaad Steve Tyler is #99 ¯\_(ツ)_/¯ \$\endgroup\$
    – Arnauld
    Commented Oct 10, 2017 at 16:46
  • \$\begingroup\$ this may help somebody but I don't have the CG skills to use the info: the 1-6, 1-8, and 3-5 letters of the names are unique combinations. \$\endgroup\$
    – Jeutnarg
    Commented Oct 10, 2017 at 17:25

19 Answers 19


Python 2, 80 71 bytes

def f(s):i=sum(map(ord,s))%98%40;return chr(i-i/26*18+i/32*3-i/37*8+65)

Try it online!

The sums of ordinals modded give numbers between 0 and 38

The numbers larger than 25 are then shifted to fill in the blanks as below (sorted sequence shown):

  0  1  2  3  4  5  6  7  8  -  -  -  - 13 14  - 16  - 18  -  -  - 22 23 24 25  - 27 28 29 30  - 32  - 34 35 36  - 38

Subtract 18 if i>25:

  0  1  2  3  4  5  6  7  8  -  -  -  - 13 14  - 16  - 18  -  -  - 22 23 24 25
                          - 27 28 29 30  - 32  - 34 35 36  - 38

Add 3 if i>31:

  0  1  2  3  4  5  6  7  8  -  -  -  - 13 14  - 16  - 18  -  -  - 22 23 24 25
                          - 27 28 29 30  
                                                  - 32  - 34 35 36  - 38

Subtract 8 if i>37:

  0  1  2  3  4  5  6  7  8  -  -  -  - 13 14  - 16  - 18  -  -  - 22 23 24 25
                          - 27 28 29 30  
                                                  - 32  - 34 35 36  
                                            - 38

Which gives the sequence 0..25

  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

These are then converted to A-Z with chr(i+65)

  • \$\begingroup\$ I think you can shorten (i>31) to i/32, etc \$\endgroup\$
    – xnor
    Commented Oct 10, 2017 at 8:58

6502 machine code routine (C64), 83 bytes

20 FD AE 20 9E AD 85 FC 20 A3 B6 A9 79 85 FB A0 00 84 FD B1 22 10 03 69 A0 18
45 FD 65 FB 85 FD E6 FB C8 C4 FC D0 EC E9 29 B0 FC 69 29 C9 1A 90 1C 29 0F C9
0D 90 04 69 09 90 12 C9 02 F0 0F C9 08 D0 04 A9 06 D0 06 C9 0C D0 02 A9 11 18
69 41 4C D2 FF

This is position-independent code, just put it somewhere in RAM and jump there, e.g. using the sys command.

Online demo (loads to $C000/49152).

Usage: sys49152,"[name]", e.g. sys49152,"Aretha Franklin".

Important: If the program was load from disk (like in the online demo), issue a new command first! This is necessary because loading a machine program trashes some C64 BASIC pointers.

Note: The C64 is by default in a mode without lowercase letters -- in order to be able to enter readable names, switch to lowercase mode first by pressing SHIFT+CBM.


The challenge is in fact to find a minimal perfect hash function for these names; for the C64, I had to find one that's easily computable in simple 8bit operations. Here's a commented disassembly listing:

.C:c000  20 FD AE    JSR $AEFD          ; consume comma
.C:c003  20 9E AD    JSR $AD9E          ; evaluate expression
.C:c006  85 FC       STA $FC            ; save string length
.C:c008  20 A3 B6    JSR $B6A3          ; free string
.C:c00b  A9 79       LDA #$79           ; value for adding during hashing
.C:c00d  85 FB       STA $FB
.C:c00f  A0 00       LDY #$00           ; offset for reading string
.C:c011  84 FD       STY $FD            ; and initial hash value
.C:c013   .hashloop:
.C:c013  B1 22       LDA ($22),Y        ; read next character from string
.C:c015  10 03       BPL .xor           ; if bit 8 set (shifted)
.C:c017  69 A0       ADC #$A0           ; translate to same unshifted character
.C:c019  18          CLC
.C:c01a   .xor:
.C:c01a  45 FD       EOR $FD            ; xor with previous hash
.C:c01c  65 FB       ADC $FB            ; add offset
.C:c01e  85 FD       STA $FD            ; store new hash
.C:c020  E6 FB       INC $FB            ; increment offset
.C:c022  C8          INY
.C:c023  C4 FC       CPY $FC
.C:c025  D0 EC       BNE .hashloop      ; repeat until last character
.C:c027   .modloop:
.C:c027  E9 29       SBC #$29           ; subtract $29 until
.C:c029  B0 FC       BCS .modloop       ; underflow, then
.C:c02b  69 29       ADC #$29           ; add once again ( => mod $29)
.C:c02d  C9 1A       CMP #$1A           ; value in hash range?
.C:c02f  90 1C       BCC .tochar        ; -> output
.C:c031  29 0F       AND #$0F           ; mask lowest 4 bits only
.C:c033  C9 0D       CMP #$0D           ; greater 12 ?
.C:c035  90 04       BCC .fixedvals     
.C:c037  69 09       ADC #$09           ; then just add 10 (9 plus carry)
.C:c039  90 12       BCC .tochar        ; and done -> output
.C:c03b   .fixedvals:
.C:c03b  C9 02       CMP #$02           ; 2 becomes 3 by adding
.C:c03d  F0 0F       BEQ .tochar2       ; with carry (jump after the CLC)
.C:c03f  C9 08       CMP #$08           ; if value was 8
.C:c041  D0 04       BNE .check2
.C:c043  A9 06       LDA #$06           ; new value is 6
.C:c045  D0 06       BNE .tochar        ; and output
.C:c046   .check2:
.C:c047  C9 0C       CMP #$0C           ; else if value was 12
.C:c049  D0 02       BNE .tochar
.C:c04b  A9 11       LDA #$11           ; new value is 17
.C:c04d   .tochar:
.C:c04d  18          CLC
.C:c04d   .tochar2:
.C:c04e  69 41       ADC #$41           ; add character code for 'a'
.C:c050  4C D2 FF    JMP $FFD2          ; jump to kernal CHROUT routine

Test suite (C64 BASIC, containing the machine code routine in data lines)

1sY49152,"Aretha Franklin":?":Aretha Franklin"
2sY49152,"Ray Charles":?":Ray Charles"
3sY49152,"Elvis Presley":?":Elvis Presley"
4sY49152,"Sam Cooke":?":Sam Cooke"
5sY49152,"John Lennon":?":John Lennon"
6sY49152,"Marvin Gaye":?":Marvin Gaye"
7sY49152,"Bob Dylan":?":Bob Dylan"
8sY49152,"Otis Redding":?":Otis Redding"
9sY49152,"Stevie Wonder":?":Stevie Wonder"
10sY49152,"James Brown":?":James Brown"
11sY49152,"Paul McCartney":?":Paul McCartney"
12sY49152,"Little Richard":?":Little Richard"
13sY49152,"Roy Orbison":?":Roy Orbison"
14sY49152,"Al Green":?":Al Green"
15sY49152,"Robert Plant":?":Robert Plant"
16sY49152,"Mick Jagger":?":Mick Jagger"
17sY49152,"Tina Turner":?":Tina Turner"
18sY49152,"Freddie Mercury":?":Freddie Mercury"
19sY49152,"Bob Marley":?":Bob Marley"
20sY49152,"Smokey Robinson":?":Smokey Robinson"
21sY49152,"Johnny Cash":?":Johnny Cash"
22sY49152,"Etta James":?":Etta James"
23sY49152,"David Bowie":?":David Bowie"
24sY49152,"Van Morrison":?":Van Morrison"
25sY49152,"Michael Jackson":?":Michael Jackson"
26sY49152,"Jackie Wilson":?":Jackie Wilson"

Online demo of test suite.


Python 2, 68 bytes

def f(n):i=hash(n)%337%125%45;return chr(65+i-i/25*2-i/29*21+i/35*2)

Try it online!

  • 1
    \$\begingroup\$ interesting to know how did you compose this \$\endgroup\$ Commented Oct 11, 2017 at 13:17
  • 3
    \$\begingroup\$ @SargeBorsch hash(n) computes an unique integer for every names. The modulo operations still keep those ints unique, but lowers their value. The second part (chr(65+i-i/25*2-i/29*21+i/35*2)) is similar to TFelds answer. The modulo operations are bruteforced by a script which I already used here and here. \$\endgroup\$
    – ovs
    Commented Oct 11, 2017 at 13:34

Javascript, 138 132 characters

As all initials are unique, except for MJ = Michael Jackson / Mick Jagger, I check for Michael Jackson specifically (the only one with an h on the 4th position), and for all other names I created a string with the initials followed by a unique letter.


Code Snippet

Try it here:

var solution =

var testnames = [
"Aretha Franklin",
"Ray Charles",
"Elvis Presley",
"Sam Cooke",
"John Lennon",
"Marvin Gaye",
"Bob Dylan",
"Otis Redding",
"Stevie Wonder",
"James Brown",
"Paul McCartney",
"Little Richard",
"Roy Orbison",
"Al Green",
"Robert Plant",
"Mick Jagger",
"Tina Turner",
"Freddie Mercury",
"Bob Marley",
"Smokey Robinson",
"Johnny Cash",
"Etta James",
"David Bowie",
"Van Morrison",
"Michael Jackson",
"Jackie Wilson"
testnames.forEach(name=>document.body.append( solution(name) ));

  • \$\begingroup\$ There may be a shorter hashing function, but I like the idea of trying something a human might do. However, I do wish you'd use the code snippet feature instead of linking to JSFiddle. \$\endgroup\$
    – trlkly
    Commented Oct 12, 2017 at 3:46
  • \$\begingroup\$ @trlkly I used the code snippet feature now. \$\endgroup\$
    – nl-x
    Commented Oct 12, 2017 at 8:19

Java (OpenJDK 8), 128 126 115 113 bytes

Not too shabby for a java submission!

Thanks to Kevin for saving me a whole lot of bytes with the lambda expressions!

s->{int a=0;for(int i:s.substring(1,6).getBytes())a+=i;a*=a==431?0.108:2.65108;return(char)(a==1341?70:a%26+65);}

Try it online!

  • 1
    \$\begingroup\$ Nice answer, +1 from me. I'm currently also working on a Java solution by creating a script.. No luck so far though. Btw, you can golf two bytes by changing {a+=i;} to a+=i; \$\endgroup\$ Commented Oct 10, 2017 at 11:28
  • 1
    \$\begingroup\$ @KevinCruijssen Cheers, can't believe I missed that! I wrote a script to try and find the 'magic number' that would give me unique values between 0 and 25 but the best I could do was 24, hence the if statements at the end. \$\endgroup\$ Commented Oct 10, 2017 at 11:35
  • 1
    \$\begingroup\$ Hmm btw, since you are using Java 8, you can also golf char g(String s) to s->. I've modified your TIO to show how to do this, in case you're only used to Java 7 methods. \$\endgroup\$ Commented Oct 10, 2017 at 11:41
  • \$\begingroup\$ Thanks, I never realised you could do that, I'll update my submission (again!) \$\endgroup\$ Commented Oct 10, 2017 at 11:44
  • \$\begingroup\$ Hahaha, you can tell I'm new to this \$\endgroup\$ Commented Oct 10, 2017 at 11:49

Python 3, 132 99 96 bytes

lambda m:chr(98+"ԇ̲ЙГ̫ѼӿИԸՋжʾҍϴЬֺΝעЕΞϾҞ֜ӣ֪".find(chr(sum(map(ord,m)))))

Try it online!

Not golfed brilliantly, but I thought I'd give this a go.

-33 bytes thanks to modifications made by TFeld.
-3 bytes by using find instead of index thanks to ovs.

  • \$\begingroup\$ You can save 6 bytes by using sum(map(ord,m)), also I added Aretha Franklin for 128 bytes \$\endgroup\$
    – TFeld
    Commented Oct 10, 2017 at 9:19
  • \$\begingroup\$ And you can use chr(97+...) instead of ascii_lowercase : 99 bytes \$\endgroup\$
    – TFeld
    Commented Oct 10, 2017 at 9:21
  • 1
    \$\begingroup\$ What about an explanation? \$\endgroup\$
    – Matsemann
    Commented Oct 10, 2017 at 13:50
  • 3
    \$\begingroup\$ An explanation: sum(map(ord,m)) adds up the ASCII values of the characters in the string m (gives integers in range 702–1506). Then calling chr it converts it to a (Unicode) character with that number: chr(702) is ʾ to chr(1506) = ע and lots in between. This solution simply looks up this character in a list of all possible (26) such characters to get the index (0–26), then returns character with ASCII code 97 + that index (so 'a' to 'z'). \$\endgroup\$ Commented Oct 11, 2017 at 0:40
  • 1
    \$\begingroup\$ Your current solution still contains a 99 byte version. You meant to use OVS's version ? \$\endgroup\$
    – nl-x
    Commented Oct 11, 2017 at 13:17

Perl, 56, 54, 50, 46 +1 (-p) bytes




Thanks to Dom's comment could save 4 more bytes, also changed to uppercase to fit better requierements.


Try It Online

  • \$\begingroup\$ Nice approach! I think you need to write/score a whole callable function though? \$\endgroup\$ Commented Oct 11, 2017 at 12:52
  • \$\begingroup\$ @FelixPalmen, it's a perl program which can be called inline : perl -pe '$_=crypt$_,mO;/..(.)/;$_=$1;y/035eft/AHPRXZ/;$_=lc' adding link to tio \$\endgroup\$ Commented Oct 11, 2017 at 13:06
  • \$\begingroup\$ Nice! Was looking for a similar approach, using $1^$2 but didn't think to use crypt... You can save 4 bytes with some re-ordering: Try it online! \$\endgroup\$ Commented Oct 11, 2017 at 13:17

PHP, 90 88 86 72+1 bytes

might become even shorter with a different modulo.


Save to file and run as pipe with -nF or try it online.

  • 2
    \$\begingroup\$ Aretha Franklin and Paul McCartney both output W on your test cases, and there is no X output. Don't know if it's an error in the code itself or just the try it online conversion :) \$\endgroup\$ Commented Oct 10, 2017 at 14:12
  • 1
    \$\begingroup\$ @crazyloonybin replacement typo fixed. Thanks for hinting. \$\endgroup\$
    – Titus
    Commented Oct 10, 2017 at 21:52
  • \$\begingroup\$ So how do I run this? Your 'try it online' code doesn't use the <?= part. And the 'Run as pipe` I'm not getting working. Also, I get notices when trying to run it from command line. \$\endgroup\$
    – nl-x
    Commented Oct 11, 2017 at 9:35
  • \$\begingroup\$ @Titus : In CodeGolf you should give the complete function or application that generates (only) the desired output. I'm familiar with <?= ... So my question still is, how do I run your code (from command line)? I fail at feeding it $argn in command line... All my tries so far either give artifacts, and still seem to require more code to get it to run. \$\endgroup\$
    – nl-x
    Commented Oct 12, 2017 at 13:03
  • \$\begingroup\$ @nl-x Your PHP yields notices, it´s because you didn´t give it the n option: echo <input> | php -nF <scriptfilename> \$\endgroup\$
    – Titus
    Commented Oct 12, 2017 at 15:10

MATL, 28 bytes

s98\40\2Y2'ijkl o qst uz'hw)

Try it online!



Implicitly get the input string. Sum the characters of the input string, and do it modulus 98 followed by modulus 40. Results in one of the following numbers: 38 18 13 34 29 23 27 30 5 28 22 1 0 16 7 32 8 14 3 36 25 4 2 6 24 35 (in order of the Pastebin list).

2Y2'ijkl o qst uz'h

Push the (lowercase) alphabet with 2Y2. This takes care of the numbers in the range [1,26]. However, some numbers are missing, and we have numbers up to 38. Hence, we append (h) a string that takes care of the higher numbers, by mapping these numbers to the 'missing' letters. The spaces can be anything, I used capital letters in my original program for my own convenience.


We can now index the number from the first step into the string from the second step with ). We use w to get the arguments in the correct order. While it may seem that we use 0-based indexing (the numbers vary from 0 to 38, and the string is 39 characters long), the reality is actually a bit more complicated: we use 1-based modular indexing, a feature unique to MATL. This means that 1 indexes to a, 38 actually indexes to u, and 0 indexes to the final z of the string.


Python 2, 50 43 bytes

Credit to japh for the new version

lambda n:chr(hash(n)%2354%977%237%54%26+65)

Try it online!

Note: This is dependent on the hash builtin and will not work in all implementations

  • \$\begingroup\$ 43 bytes: lambda n:chr(hash(n)%2354%977%237%54%26+65) \$\endgroup\$
    – japh
    Commented Oct 14, 2017 at 10:04
  • \$\begingroup\$ @japh Nice! My python brute force checker clearly wasn't fast enough ;) \$\endgroup\$
    – KSab
    Commented Oct 14, 2017 at 10:43

Ruby, 63 bytes


Adds the ascii codes of the input, takes them mod 98 and then mod 66 to get a one of 26 unique numbers n in the range 0..65. The huge hexadecimal number contains a 1 bit in each of these 26 places, so by rightshifting it by n we obtain a number with 1..26 1 bits in it. We count the 1 bits by adding the ascii codes and taking mod 48, then add 64 and convert to an ASCII code.

Test program

the map iterates through the singers printing the letter code and singer. It then returns an array of the letter codes, which is sorted to demonstrate that each letter is used once.

a= [
  "Aretha Franklin","Ray Charles",
  "Elvis Presley","Sam Cooke",
  "John Lennon","Marvin Gaye",
  "Bob Dylan","Otis Redding",
  "Stevie Wonder","James Brown",
  "Paul McCartney","Little Richard",
  "Roy Orbison","Al Green",
  "Robert Plant","Mick Jagger",
  "Tina Turner","Freddie Mercury",
  "Bob Marley","Smokey Robinson",
  "Johnny Cash","Etta James",
  "David Bowie","Van Morrison",
  "Michael Jackson","Jackie Wilson"

p a.map{|i|p [f[i],i];f[i]}.sort


["S", "Aretha Franklin"]
["E", "Ray Charles"]
["R", "Elvis Presley"]
["J", "Sam Cooke"]
["X", "John Lennon"]
["C", "Marvin Gaye"]
["M", "Bob Dylan"]
["W", "Otis Redding"]
["V", "Stevie Wonder"]
["Y", "James Brown"]
["D", "Paul McCartney"]
["Q", "Little Richard"]
["Z", "Roy Orbison"]
["P", "Al Green"]
["O", "Robert Plant"]
["K", "Mick Jagger"]
["N", "Tina Turner"]
["L", "Freddie Mercury"]
["G", "Bob Marley"]
["I", "Smokey Robinson"]
["A", "Johnny Cash"]
["F", "Etta James"]
["H", "David Bowie"]
["U", "Van Morrison"]
["B", "Michael Jackson"]
["T", "Jackie Wilson"]
["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] 

Octave, 85 83 80 74 bytes

@(n)('A':'Z')(mod(n([1 2 8])*[1;15;47],124)=='#iZo,gp<C&4Y1!8-G`Kn3wtTIO')

This mess of an anonymous is the result of some messing around in MATLAB trying to find a good way to encode the data.

Basically after a quick analysis, only letters 1,2, and 8 of the input string (smallest string is 8 chars, so we are good) are needed to produce a unique value from each input. The hard part is then converting that unique value into something usable.

MATLAB is terrible at compressing data, so I had to look for another way to make the lookup mapping. I set out trying to find some function on the three input letters that resulted in a unique value that was also a printable ASCII value so that I could embed the mapping in a string of one character per input.

It turns out that matrix multiplying the characters at index [1 2 8] by the integer matrix [1;15;47] and then performing mod 124 results in unique values which all printable ASCII (and none are a ' character which would bugger up string literals). Pleasingly the mapping ends with TIO which is completely accidental. Interestingly this is the only mapping for this equation that gives 26 unique printable ASCII characters.

So basically that is my lookup mapping and calculation. Doing the lookup is simply a case of performing the calculation and comparing with the mapping. Adding on 'A'-1 to the index in the map results in a character A-Z.

You can try it online on TIO, which shows the full mapping of inputs and outputs. For completeness the full mapping is also below:

'Aretha Franklin' ==> B
'Ray Charles'     ==> S
'Elvis Presley'   ==> F
'Sam Cooke'       ==> V
'John Lennon'     ==> L
'Marvin Gaye'     ==> N
'Bob Dylan'       ==> C
'Otis Redding'    ==> Q
'Stevie Wonder'   ==> X
'James Brown'     ==> I
'Paul McCartney'  ==> R
'Little Richard'  ==> M
'Roy Orbison'     ==> T
'Al Green'        ==> A
'Robert Plant'    ==> U
'Mick Jagger'     ==> P
'Tina Turner'     ==> Y
'Freddie Mercury' ==> H
'Bob Marley'      ==> D
'Smokey Robinson' ==> W
'Johnny Cash'     ==> K
'Etta James'      ==> G
'David Bowie'     ==> E
'Van Morrison'    ==> Z
'Michael Jackson' ==> O
'Jackie Wilson'   ==> J

  • Saved 2 bytes tweaking mapping to remove +32.
  • Saved 3 bytes by making Octave-only using logical indexing of 'A':'Z' rather than find.
  • Saved 6 bytes by doing sum of multiplications using matrix multiplication.
  • \$\begingroup\$ Clever approach, maybe too clever? 53 bytes, based on my MATL answer \$\endgroup\$
    – Sanchises
    Commented Oct 12, 2017 at 6:47
  • \$\begingroup\$ @Sanchises possibly, but it was the approach I came up with ¯_(ツ)_/¯. You're welcome to post your version as a separate answer. \$\endgroup\$ Commented Oct 12, 2017 at 7:25
  • \$\begingroup\$ I figured, and I agree that it's more interesting to have different approaches than just copy the shortest approach. I just wanted to compare the approaches, I think yours is more clever but I suppose the dataset just allowed for an easy mod-based approach (not sure if that's a coincidence or statistically likely) \$\endgroup\$
    – Sanchises
    Commented Oct 12, 2017 at 8:12

JavaScript (Chrome), 102

Note Unfortunately it works only in Chrome, because of implementation-dependent approximations in parseInt() (thanks @Arnauld)

s=>s[0]=='L'?'z':"ab.c..defghijklmn...o..pqrst.u.vwxy"[parseInt(s.replace(/ /,'o').slice(0,14),36)%35]

I looked for a hash function, taking a slice of each name, converting to numbers using base 36 and then applying a modulo.

I used this code to look for the best hash:

x=`Al Green\nAretha Franklin\nBob Dylan\nBob Marley\nDavid Bowie\nElvis Presley\nEtta James\nFreddie Mercury\nJackie Wilson\nJames Brown\nJohn Lennon\nJohnny Cash\nLittle Richard\nMarvin Gaye\nMichael Jackson\nMick Jagger\nOtis Redding\nPaul McCartney\nRay Charles\nRobert Plant\nRoy Orbison\nSam Cooke\nSmokey Robinson\nStevie Wonder\nTina Turner\nVan Morrison`.split(`\n`)

        S=new Set();
        f=k ? (k-1).toString(36) : ''
        x.forEach(x=>(n=parseInt(x.replace(/ /,f).slice(i,j),36)%m, S.add(n)))
        if (S.size > max) console.log(i,j,f,m,max=S.size)

And the results:

0 1 "" 26 14
0 2 "" 26 15
0 4 "" 26 16
0 5 "" 26 18
0 6 "0" 26 19
0 6 "3" 26 20
0 8 "a" 26 21
2 5 "7" 28 23
0 14 "h" 35 24
0 14 "o" 35 25
2 9 "" 51 26

The best hash function gives 26 different values between 0 and 50, but I used a different one, with 1 duplicate but a smaller range.


var names=x=`Al Green\nAretha Franklin\nBob Dylan\nBob Marley\nDavid Bowie\nElvis Presley\nEtta James\nFreddie Mercury\nJackie Wilson\nJames Brown\nJohn Lennon\nJohnny Cash\nLittle Richard\nMarvin Gaye\nMichael Jackson\nMick Jagger\nOtis Redding\nPaul McCartney\nRay Charles\nRobert Plant\nRoy Orbison\nSam Cooke\nSmokey Robinson\nStevie Wonder\nTina Turner\nVan Morrison`.split(`\n`)

var F=
s=>s[0]=='L'?'z':"ab.c..defghijklmn...o..pqrst.u.vwxy"[parseInt(s.replace(/ /,'o').slice(0,14),36)%35]

var Singers={}

;Object.keys(Singers).sort().forEach(i=> console.log(i, Singers[i]))

  • \$\begingroup\$ You may want to mention that it only works on Chrome because of implementation-dependent approximations in parseInt(). \$\endgroup\$
    – Arnauld
    Commented Oct 11, 2017 at 15:31
  • \$\begingroup\$ @Arnauld thanks, I did not know. \$\endgroup\$
    – edc65
    Commented Oct 11, 2017 at 19:27

C, 65 55 49 bytes



Same approach as KSab's answer. C doesn't provide a string hash function like Python. Or does it?


Try it online!

h returns an int whose values are the ASCII codes for A .. Z.


APL (Dyalog), 48 bytes

⎕A[' $%&().279<?@CL'⍳⎕UCS 78|7⊥⎕UCS⍞]

Assumes ⎕IO←0 (array indexing set to start from 0 instead of 1).

Try it online!


It's a complete program; the outer part ⎕A[] is indexing somewhere into the uppercase alphabet to get the output character. Inside the brackets it reads right-to-left, and is a prompt for a string input. ⎕UCS turns that into Unicode char values. 78|7⊥ decodes those values as if they were digits in base 7, then takes the answer modulo 78 (brute forced to find a base and modulo combination which give usable ASCII character values). ⎕UCS again to turn that single number into a character, and look it up in the magic string '...' of 26 identifier characters. That position becomes the index into the ⎕A[] uppercase alphabet. (There are control chars in the string, the ASCII codes are 11 14 18 20 22 23 24 25 26 30 31 32 36 37 38 40 41 46 50 55 57 60 63 64 67 76).

The full mapping is:

      singers←'Aretha Franklin' 'Al Green' 'Ray Charles' 'Robert Plant' 'Elvis Presley' 'Mick Jagger' 'Sam Cooke' 'Tina Turner' 'John Lennon' 'Freddie Mercury' 'Marvin Gaye' 'Bob Marley' 'Bob Dylan' 'Smokey Robinson' 'Otis Redding' 'Johnny Cash' 'Stevie Wonder' 'Etta James' 'James Brown' 'David Bowie' 'Paul McCartney' 'Van Morrison' 'Little Richard' 'Michael Jackson' 'Roy Orbison' 'Jackie Wilson'

      f←{⎕A[' $%&().279<?@CL'⍳⎕UCS 78|7⊥⎕UCS⍵]}
      ¯1⌽' ',(↑singers),f¨singers
↓P Aretha Franklin│
│J Al Green       │
│M Ray Charles    │
│N Robert Plant   │
│U Elvis Presley  │
│Z Mick Jagger    │
│L Sam Cooke      │
│G Tina Turner    │
│F John Lennon    │
│B Freddie Mercury│
│Q Marvin Gaye    │
│H Bob Marley     │
│K Bob Dylan      │
│C Smokey Robinson│
│D Otis Redding   │
│T Johnny Cash    │
│Y Stevie Wonder  │
│I Etta James     │
│X James Brown    │
│O David Bowie    │
│E Paul McCartney │
│V Van Morrison   │
│A Little Richard │
│S Michael Jackson│
│R Roy Orbison    │
│W Jackie Wilson  │

And the sorted letters of the mapping is exactly the uppercase alphabet (no dupes or missing):


      (⊂∘⍋⌷⊢) f¨singers    ⍝ sorted

      ⎕A ≡ (⊂∘⍋⌷⊢) f¨singers    ⍝ matches the alphabet     
  • \$\begingroup\$ As you have unprintables in the code (which are out of the SBCS), I think the score should be in UTF-8 (60 bytes). Also, you can safely remove the last char in the lookup table for , saving a byte. \$\endgroup\$
    – Bubbler
    Commented Sep 8, 2020 at 10:16

Javascript, 98 bytes

s=l=>("heCysvCm hirDb iiesm ultOyr rb c ndeMbeonh tdvMnacic".indexOf(l[4]+l[2])/2+10).toString(36)

I found that the combination of the 2nd and the 4th character of the names is unique for each of them.

Therefore I create a string with the combinations of name[4] + name[2], not name[2] + name[4] or I would have a repetition of the char group eh of the first name Aretha Franklin eh and when Smokey Robinson and Johnny Cash oehn are concatenated.

I could just move Johnny Cash to another position of the string and get a different mapping, but concatenating the 4th and the 2nd character in this order avoids the collision and leaves the dataset order intact without adding more length to the solution. So I decided to go that way (it's just personal preference)

I search for the position of the concatenation of the 4nd and 2nd letter of the given parameter in the string and divide it by 2 so that I get a number between 0 and 25. Then I add 10 and convert it to string from base 36, where 10 corresponds to a and 35 to z

let singers = [
  "Aretha Franklin",
  "Ray Charles",
  "Elvis Presley",
  "Sam Cooke",
  "John Lennon",
  "Marvin Gaye",
  "Bob Dylan",
  "Otis Redding",
  "Stevie Wonder",
  "James Brown",
  "Paul McCartney",
  "Little Richard",
  "Roy Orbison",
  "Al Green",
  "Robert Plant",
  "Mick Jagger",
  "Tina Turner",
  "Freddie Mercury",
  "Bob Marley",
  "Smokey Robinson",
  "Johnny Cash",
  "Etta James",
  "David Bowie",
  "Van Morrison",
  "Michael Jackson",
  "Jackie Wilson"

s=l=>("heCysvCm hirDb iiesm ultOyr rb c ndeMbeonh tdvMnacic".indexOf(l[4]+l[2])/2+10).toString(36)

singers.forEach(singer => console.log(s(singer), singer))

  • \$\begingroup\$ very cleaver the combination you found! \$\endgroup\$
    – Joyal
    Commented Oct 12, 2017 at 13:05
  • \$\begingroup\$ aaah yes. off course. i have something quite similar, but instead of adding the char to return in the string, the position of the occurance could save 25 chars. Clever! \$\endgroup\$
    – nl-x
    Commented Oct 12, 2017 at 16:08

Wolfram Language (Mathematica), 101 126 bytes

Alphabet[][[#&@@#&@@Position[(t=ToCharacterCode)@"nZ-Be_;f%d^q 0w@x~KDaLJ&`k",Total@t@#~Mod~98+32]]]&

+32 seems leading to the shortest stirng hashtable in Mathematica InputForm.

Try it online!


Excel, 96 bytes

After too much time wasted trying other approaches, have implemented @Eduardo Paez's approach:

=CHAR(FIND(MID(A1,5,1)&MID(A1,3,1),"her DbMbdvsv tdeicsm hnhltirac c i uCyrbOyCmeoie nMn")/2+65)

///, 390 231 bytes

/ F//
/A //
/ G//
/ M//
/M //
/J B/X/
/J //
/L //
/ R//
/R C/Y/
/S C/Z/
/B D/K/
/ B//
/ J//
/ T//
/S W/I/
/R O/N/
/R //
/E P/H/

Try it online!

231 bytes after removing the newlines.

This is very long, but /// cannot handle different characters generically. In other words, /// does not support regex.


Your Answer

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

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