12
\$\begingroup\$

The challenge is to make a program that sorts a list of words, only that the words need to be in the order of a random given alphabet.

Your program will accept a string of comma-separated words and a new alphabet.
Your program will output every word in the same way in the new sorted order.

Example:

Input:

home,oval,cat,egg,network,green bcdfghjklmnpqrstvwxzaeiouy

Output:

cat,green,home,network,egg,oval

This is a , so the winner is the person with the shortest program.

This is my first challenge so any improvements to the question/challenge are appreciated.

\$\endgroup\$
6
  • \$\begingroup\$ 1. I take from your example that the alphabet will be separated from the words by a space. Is that correct? 2. Will the words always be in lowercase? \$\endgroup\$
    – Dennis
    Oct 4, 2014 at 20:51
  • \$\begingroup\$ @Dennis yes to both \$\endgroup\$
    – Mathetic
    Oct 4, 2014 at 20:53
  • 1
    \$\begingroup\$ That is a mistake. I will edit that. \$\endgroup\$
    – Mathetic
    Oct 4, 2014 at 21:24
  • 1
    \$\begingroup\$ +1 OK question (for a first try ;-)). But I'm not seeing the relevance of the title - perhaps you can rename it to Sort by custom alphabet or something more creative? \$\endgroup\$ Oct 4, 2014 at 21:45
  • 7
    \$\begingroup\$ May we take the inputs in a form that is more appropriate to the language? E.g. two separate inputs; a character matrix with one word on each line, and a character vector of letters. A list of strings. Etc. \$\endgroup\$
    – Adám
    Mar 10, 2016 at 17:21

14 Answers 14

4
\$\begingroup\$

Bash+coreutils, 37 bytes

tr ,$2 \\na-z<<<$1|sort|tr \\na-z ,$2

Output:

$ ./alphasort.sh home,oval,cat,egg,network,green bcdfghijklmnpqrstvwxyzaeiouy
cat,green,home,network,egg,oval, $ 
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice way of dealing with the commas! \$\endgroup\$
    – Dennis
    Oct 4, 2014 at 21:41
2
\$\begingroup\$

CJam, 26 19 17 bytes

rr:A;',/{Af#}$',*

Try it online.

Test case

$ cjam sort.cjam <<< 'home,oval,cat,egg,network,green bcdfghjklmnpqrstvwxzaeiouy'
cat,green,home,network,egg,oval

How it works

rr                    " Read two whitespace-separated tokens from STDIN. ";
  :A;                 " Save the second token (the alphabet) in A.       ";
     ',/              " Split the remaining token at commas.             ";
        {Af#}$        " Sort by the chunks' characters' indexes in A.    ";
               ',*    " Join, separating by commas.                      ";
\$\endgroup\$
3
  • \$\begingroup\$ Well, since u also made used the same approach, mine doesn't really make any sense now. \$\endgroup\$
    – Optimizer
    Oct 4, 2014 at 21:11
  • \$\begingroup\$ @Optimizer: You beat me by eight seconds. If you undelete your answer, I'll roll mine back. \$\endgroup\$
    – Dennis
    Oct 4, 2014 at 21:16
  • \$\begingroup\$ No, I think its a trivial and very obv change. I should have looked at your updates before posting my answer in the first place :) \$\endgroup\$
    – Optimizer
    Oct 4, 2014 at 21:17
2
\$\begingroup\$

Pyth, 19 characters

j\,o_mx_zdNchczd\,

Test:

$ pyth -c "j\,o_mx_zdNchczd\," <<< 'home,oval,cat,egg,network,green bcdfghjklmnpqrstvwxzaeiouy'
cat,green,home,network,egg,oval

Explanation:

                            Implicit: d=" "
                            Implicit: z=input()
j\,                         ",".join(
   o                                 order_by(lambda N:
    _                                                  rev(
     m                                                     map(lambda d:
      x_zd                                                              rev(z).index(d),
      N                                                                 N),
    chczd\,                                            z.split(" "[0].split(",")

Essentially, it sorts the chunks, with a key of the list of indexes of the characters in the string, then joins them on commas. The reversal businesses is shorter than spliting the string again.

\$\endgroup\$
2
  • \$\begingroup\$ 18 bytes: j\,_omx_zdNchczd\, \$\endgroup\$
    – Dennis
    Oct 5, 2014 at 15:43
  • \$\begingroup\$ @Dennis very clever, thank you. \$\endgroup\$
    – isaacg
    Oct 5, 2014 at 20:48
2
+200
\$\begingroup\$

R, 49 bytes

function(w,a,`[`=chartr)"a-z"[a,sort(a["a-z",w])]

Try it online!

Translates words from given alphabet to a-z, then sorts and then translates back.

Uses flexible I/O rules (vector of words and alphabet as string).


With strict I/O rules it goes up by a lot (R is not very good with strings):

R, 112 bytes

function(s,`/`=strsplit,t=el(s/" "))paste(chartr("a-z",t[2],sort(chartr(t[2],"a-z",el(t[1]/",")))),collapse=",")

Try it online!

Here we do the splitting of the input string inside the function.
First, we redefine / to be strsplit. It always returns a list, so we will need to extract the first element (which is shortest done by el). We split the words from the alphabet on and then the words themselves on ,.
Then we do the same trick as in the main answer.
At the end we collapse the whole vector with , using paste.


With many strange function redefinitions:

R, 111 bytes

function(s,`?`=el,`[`=chartr,`/`=strsplit,t=?s/" ")paste("a-z"[t?2,sort((t?2)["a-z",?(t?1)/","])],collapse=",")

Try it online!

Here we also redefine [ to be chartr, so we cannot use [ to subscript t anymore, but we can use el for this purpose.
This leads us also to redefining ? to be el (after some trial and error with operator precedence). It is worth noting, that ? can act as binary and unary operator and has the lowest precedence of all.

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

K (ngn/k), 23 bytes

{","/x@<y?x:","\x}." "\

Try it online!

Takes input as outlined in question.

  • " "\ split input on the space, into the list of comma-delimited words and the (shuffled) alphabet
  • {...}. call the function with the list of words as the first arg (x) and the alphabet as the second arg (y)
  • x:","\x split the string of comma-delimited words into a list of the words themselves, updating the x variable
  • y?x look up the index of each character in each word in the shuffled alphabet
  • x@< grade the resulting list of lists of indices, and apply the sort order to the list of words
  • ","/ join the individual words with commas

K (ngn/k), 8 bytes

{x@<y?x}

Try it online!

Assumes more lenient input/output format; a first arg x of a list of words, and a second arg y containing the shuffled alphabet. A list of strings is returned instead of a comma-delimited string.

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

Ruby, 53 50 bytes

a,b=$*
$><<a.split(?,).sort_by{|w|w.tr b,'a-z'}*?,

I'm using Ruby's tr to replace the custom alphabet with a-z before sorting. Input is via command-line argument.

\$\endgroup\$
2
  • \$\begingroup\$ You can shave off a byte if you use $><< to print to screen (you can remove the space then). You can shave off another two bytes by assigning $* to variables like so: a,b=$* and using #sort_by instead of #sort_by!. \$\endgroup\$
    – britishtea
    Oct 5, 2014 at 20:10
  • \$\begingroup\$ @britishtea Thanks. I thought I would need *$* (which I had at first and which is the same length). \$\endgroup\$ Oct 5, 2014 at 20:32
1
\$\begingroup\$

05AB1E, 15 bytes

#`U',¡ΣXsSk}',ý

Try it online.

With less restricted I/O rules, this could have been 2 (or 3) bytes:

Explanation:

#            # Split the (implicit) input-string by spaces
 `           # Pop and push both strings separated to the stack
  U          # Pop the alphabet-string, and store it in variable `X`
   ',¡      '# Split the words-string on ","
      Σ      # Sort this list of words by:
       X     #  Push the alphabet-string `X`
        s    #  Swap so the current word is at the top of the stack again
         S   #  Convert it to a list of characters
          k  #  Get the index of each character in the alphabet-string
      }',ý  '# After the sort-by: join this list of words with "," delimiter
             # (after which this string is output implicitly as result)

Σ            # Sort the first (implicit) input-list of character-lists by:
 k           #  Index each character into the second (implicit) alphabet-string
             # (after which the sorted list of character-lists is output implicitly)
\$\endgroup\$
3
  • \$\begingroup\$ Technically, isn't 05AB1E newer than the challenge? \$\endgroup\$
    – pajonk
    Oct 20, 2021 at 16:11
  • 1
    \$\begingroup\$ @pajonk It is, but since mid 2017 that doesn't matter anymore. Newer languages are allowed to answer challenges without adding a "non-competing". \$\endgroup\$ Oct 20, 2021 at 16:17
  • \$\begingroup\$ thanks for the update, I somehow missed that. \$\endgroup\$
    – pajonk
    Oct 20, 2021 at 16:42
1
\$\begingroup\$

Clojure, 115 50 bytes

Oh, an edit five years later :D And actually in the past I out-golfed myself, now I used (map char(range 97 123)) to generate the a - z sequence but my original answer just re-uses the alphabet input via (sort %2). Well this new answer requires a more liberal input format, namely the first argument is a list of words.

#(map(fn[i](str(mapv(zipmap %2(sort %2))i)))%)

I had to re-discover that vectors don't sort neatly, but this can be avoided by casting them to strings. And not by using clojure.string/join or apply str, they sort just fine as string representations of the vector! Change the sort-by to map and you get:

(def f #(map(fn[i](str(mapv(zipmap %2(sort %2))i)))%))

(f ["home", "oval", "cat", "egg", "network", "green"] "bcdfghjklmnpqrstvwxzaeiouy")

("[\\f \\x \\j \\v]"
 "[\\x \\q \\u \\i]"
 "[\\b \\u \\p]"
 "[\\v \\e \\e]"
 "[\\k \\v \\p \\r \\x \\n \\h]"
 "[\\e \\n \\v \\v \\k]")

TIO

Original answer:

#(apply str(butlast(interleave(sort-by(fn[w](apply str(map(zipmap(sort %2)%2)w)))(re-seq #"[a-z]+"%))(repeat \,))))

Wow, this started of well with (sort-by(fn[w](mapv(zipmap(sort %2)%2)w))) but then I realized vec don't get sorted the same way as strings, and interleaving those commas takes significant amount of code as well.

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

Python, 131

w,a=input().split()
print(",".join(sorted(w.split(","),key=lambda s:"".join(["abcdefghijklmnopqrstuvwxyz"[a.find(c)]for c in s]))))

There should be plenty of room for improvement.

\$\endgroup\$
1
  • \$\begingroup\$ You don't have to use a key as the sort function - just use the list of a.find(c) directly. \$\endgroup\$
    – isaacg
    Oct 5, 2014 at 10:07
0
\$\begingroup\$

JavaScript (E6) 102 119

Sort with a mapping function 'M' based on the alphabet in variable 'a'
With IO using popup (prompt + alert)

x=prompt().split(/[ ,]/),
a=x.pop(),
M=w=>[10+a.search(c)for(c of w)]+'',
alert(x.sort((a,b)=>M(a)>M(b)))

As a (testable) function with 1 string parameter, returning a string array (92)

F=x=>(
  M=w=>[10+a.search(c)for(c of w)],
  x=x.split(/[ ,]/),
  a=x.pop(),
  x.sort((a,b)=>M(a)>M(b))
)

Test In FireFox/FireBug console

F('home,oval,cat,egg,network,green zyxwvtsrqpnmlkjhgfdcbaeiou')

Output

["network", "home", "green", "cat", "egg", "oval"]
\$\endgroup\$
6
  • 1
    \$\begingroup\$ -4 if you replace your sort function with (M(a)>M(b))-(M(a)<M(b)) \$\endgroup\$
    – DocMax
    Oct 5, 2014 at 5:48
  • \$\begingroup\$ @DocMax very nice. It turns out that it's even simpler than that (stackoverflow.com/a/7232172/3640407) \$\endgroup\$
    – edc65
    Oct 5, 2014 at 8:26
  • \$\begingroup\$ If you reuse prompt for input and output and alias it you can avoid the split call by taking the inputs separately. I think that should save a few characters. \$\endgroup\$
    – Ingo Bürk
    Oct 5, 2014 at 13:45
  • \$\begingroup\$ Also I'm only on my phone right now but why is M so complex? Wouldn't it work to use M=w=>[...a].indexOf(w)? I can't test it right now, unfortunately. \$\endgroup\$
    – Ingo Bürk
    Oct 5, 2014 at 13:47
  • \$\begingroup\$ @IngoBürk w is a word, not a character. M replace each character in w with its position in a. \$\endgroup\$
    – edc65
    Oct 5, 2014 at 14:04
0
\$\begingroup\$

Pip, 15 bytes

b@?^_SKa^',J:',

Takes the two inputs as command-line arguments. Try it online!

Explanation

b@?^_SKa^',J:',
       a         ; First command-line arg (list of words)
        ^',      ; Split on commas
     SK          ; Sort by the following key function:
   ^_            ;   Split the word into a list of letters
 @?              ;   Get the index of each letter in
b                ;   The second command-line arg (alphabet)
           J:',  ; Join the resulting list on commas
\$\endgroup\$
0
\$\begingroup\$

Japt, 12 bytes

¸Îq, nU¸Ì q,

Try it

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

Zsh, 24 bytes

tr $1 a-z|sort|tr a-z $1

Attempt This Online!

If we must use the OP's inane I/O format, 37 bytes:

tr $2, a-z\\n<<<$1|sort|tr a-z\\n $2,

Attempt This Online!

If a trailing comma is not allowed either, append |head -c-1 for +10 bytes.

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

Python 3, 50 bytes

With flexible input :

lambda w,a:sorted(w,key=lambda s:[*map(a.find,s)])

Try it online!

Python 3, 71 bytes

With strict input format :

lambda x:sorted(x[:-27].split(","),key=lambda s:[*map(x[-26:].find,s)])

Try it online!

Both can be shortened by 3 bytes in python 2 by removing [* ] arround the map

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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