6
\$\begingroup\$

Introduction

So John finally has his holidays! And what better could he do than watching some movies. He indeed has a lot of movies to watch, but he is unable to decide which one to watch first. He has a list of movies, each in the format: <Movie name> (<Year>). So he makes a simple set of rules to decide his order of watching movies.

1) The first preference is given to the release year. If a movie released a year or earlier than others, then he would watch them first.

2) If two or more movies released in the same year, and one of them begins with a number, then he would prefer to watch that movie first.

3) If two or more movies released in the same year begin with a number as well, then the movie which comes first on the original list would be watched first.

4) If two or more movies released in the same year begin with a letter, then the movie beginning with a letter which comes earlier in the English alphabet will be chosen first. If two movies begin with the same letter, then the one containing a lesser number of characters in the movie name(including spaces) will be chosen first.

5) If the number of characters is also same, then the movie which comes later in the original list would be watched first.

Well, what a great set of rules indeed. Now the challenge.

Challenge

The input will be a list of movies, i.e, strings - all following the specified format, and you need to output the sorted list, following the above stated rules. Be case insensitive , i.e, treat both uppercase and lower case characters equally and assume all inputs to be valid, and the list will contain no duplicate elements. Also, every character in the movie name is either a letter, or a number and there are blank spaces only in between. You can assume the release year is 4 digits long.

Examples

Input
Output

['The Town (2010)', 'The Prestige (2006)', 'The Departed (2006)'] 
['The Departed (2006)', 'The Prestige (2006)', 'The Town (2010)']

['Hello (2001)', '15 minutes (2001)', '25 Minutes (2002)']
['15 minutes (2001)', 'Hello (2001)', '25 Minutes (2002)']

['15 (1960)', '25 days (1960)']
['15 (1960)', '25 days (1960)']

['Jjjj (2004)', 'Hello (2004)']
['Hello (2004)', 'Jjjj (2004)']

['all gone (2018)', 'Be careful (2018)']
['all gone (2018)', 'Be careful (2018)']

['Be careful (2018)', 'all gone (2018)']
['all gone (2018)', 'Be careful (2018)']

Scoring

This is , so the shortest code wins!

\$\endgroup\$
  • 1
    \$\begingroup\$ "i.e. be case in-sensitive" - does this mean "treat upper and lowercase characters from the input as equal" or does it mean "you may assume input will always be in a single case" or does it mean "it does not matter how you compare different cases" or does it mean something else? (none of the examples help decipher it) \$\endgroup\$ – Jonathan Allan Mar 10 '18 at 16:02
  • 1
    \$\begingroup\$ @JonathanAllan I think "case insensitive" says it all. In addition to that, <Movie name> and all the examples are mixed case. \$\endgroup\$ – Titus Mar 10 '18 at 17:08
  • 1
    \$\begingroup\$ It was autocorrect. I just realised it when editing finished. Fixed now \$\endgroup\$ – Manish Kundu Mar 10 '18 at 17:40
  • 1
    \$\begingroup\$ @Titus depends. Like what stuff. \$\endgroup\$ – Manish Kundu Mar 10 '18 at 18:08
  • 1
    \$\begingroup\$ @Titus yes, that's acceptable. \$\endgroup\$ – Manish Kundu Mar 10 '18 at 18:36
3
\$\begingroup\$

Python 3, 115 bytes

lambda a:sorted(a[::-1],key=lambda s:(s.split()[-1],-("/"<s[0]<":"),a.index(s)*("/"<s[0]<":"),s[0].lower(),len(s)))

Try it online!

-11 bytes thanks to spec change (thanks Jonathan Allan for pointing it out)
-6 bytes thanks to Lynn

\$\endgroup\$
  • \$\begingroup\$ I believe that since it has been confirmed that the year is guaranteed to be four digits that you could replace int(s.split()[-1][1:-1]) with s.split()[-1] \$\endgroup\$ – Jonathan Allan Mar 10 '18 at 15:44
  • \$\begingroup\$ @JonathanAllan cool, thanks! \$\endgroup\$ – HyperNeutrino Mar 10 '18 at 15:54
  • \$\begingroup\$ A new rule clarification has made this solution invalid (it should be case-insensitive). \$\endgroup\$ – Erik the Outgolfer Mar 10 '18 at 16:47
  • \$\begingroup\$ Unfortunately (due to clarification of the intended meaning of "be case in-sensitive") this fails for ['all low (2018)','B movie (2018)'] \$\endgroup\$ – Jonathan Allan Mar 10 '18 at 17:28
  • \$\begingroup\$ @EriktheOutgolfer thanks fixed \$\endgroup\$ – HyperNeutrino Mar 10 '18 at 18:09
2
\$\begingroup\$

PHP, 231 115 113 bytes

PHP sort stabilized by using keys including the position

while($s=$argv[++$i])$a[substr($s,-6).($s<A?:$s&_).str_pad($s<A?$i:$argc-$i,$argc,0,0)]=$s;ksort($a);print_r($a);

Run with php -nr '<code>' 'movie1 (year1)' 'movie2 (year2)' ... or try it online.

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

R, 95 87 85 bytes

-2 thanks to Wheat Wizard

function(v)v[order(unlist(regmatches(v,gregexpr("[0-9]{4}",v))),tolower(v),nchar(v))]

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Hello and welcome to the site! I don't know R so I might be wrong here but I don't think you need the f=. It looks like you are making an anonymous function and assigning it to a variable. If this is an anonymous function that can be called in line you can get rid of the assignment. \$\endgroup\$ – Sriotchilism O'Zaic Mar 13 '18 at 16:02
  • \$\begingroup\$ you're right, it worked thanks! \$\endgroup\$ – DS_UNI Mar 13 '18 at 16:16
  • \$\begingroup\$ What is the purpose of tolower ? \$\endgroup\$ – JayCe Jun 13 '18 at 17:32
1
\$\begingroup\$

Jelly, 35 bytes

³i
ḲṪ$ḊṖV;1ịeØDƲ×Çṭ1Ɗ;Œlḷ/$;L;ÇN$µÞ

Try it online!

-4 bytes thanks to Mr. Xcoder

\$\endgroup\$
  • \$\begingroup\$ Perhaps 34 bytes? \$\endgroup\$ – Mr. Xcoder Mar 10 '18 at 7:27
  • \$\begingroup\$ And 33 bytes using a helper link (saves a byte from the 34-byte version, but if that’s not valid, then you can use these in your solution to get 35). Other than this, you can use ḷ\ instead of 1i$ to save another byte. \$\endgroup\$ – Mr. Xcoder Mar 10 '18 at 7:28
  • \$\begingroup\$ @Mr.Xcoder It's ḷ/, not ḷ\. ḷ\ is the same as ḷ/WẋLƲ. \$\endgroup\$ – Erik the Outgolfer Mar 10 '18 at 15:28
  • \$\begingroup\$ @EriktheOutgolfer I don’t think it matters here though. \$\endgroup\$ – Mr. Xcoder Mar 10 '18 at 15:33
  • \$\begingroup\$ @EriktheOutgolfer not sure it makes a difference, but thanks, I fixed it \$\endgroup\$ – HyperNeutrino Mar 10 '18 at 15:34
1
\$\begingroup\$

Red, 108 bytes

func[b][s: copy[]foreach m b[append/only s reverse split m"("]foreach m sort/all s[print rejoin[m/2"("m/1]]]

Try it online!

Explanation:

f: func[b] [                                 the argument is a block of strings
    s: copy []                               prepare an empty block
    foreach m b [                            for each string in the input block
       append/only s reverse split m "("     split it on "(" and append in reversed order
    ]  
    foreach m sort/all s [                   sort the new block
       print rejoin[m/2 "(" m/1]             and print it in the right order
    ]
]

Red's sort/all (sort function with refinement all) performs a stable sort, comparing all the fields of a compound argument:

sort/all [[1 2 3 1] [1 1 6] [2 1 3] [1 2 3 4]]
== [[1 1 6] [1 2 3 1] [1 2 3 4] [2 1 3]]
\$\endgroup\$
1
\$\begingroup\$

Jelly,  28 26 25  24 bytes

-1 thanks to Erik the Outgolfer (use a zip to replace pair then transpose)

µḲṚż>”<aŒlƲḢO;L;⁹iNƊȧ\ðÞ

A monadic link taking and returning lists of lists of characters.

Try it online! - footer reformats the result like the input (which is interpreted as a list of lists of characters)

...or see a test-suite

How?

µḲṚż>”<aŒlƲḢO;L;⁹iNƊȧ\ðÞ - Link: list of lists of characters, X
                                                     e.g. ["RV (2006)", "iChannel (2006)", "300 (2006)"]
                      ðÞ - sort by the following ðyadic key function (right is now X)
µ                        - ...start a monadic chain (left is now an item in X):
 Ḳ                       -   split at spaces              ["RV","(2006)"] / ["iChannel","(2006)"] / ["300","(2006)"]
  Ṛ                      -   reverse                      ["(2006)","RV"] / ["(2006)","iChannel"] / ["(2006)","300"]
          Ʋ              -   last four links as a monad:
     ”<                  -     literal '<' character (resides between digits*  and alphas ...* also the spaces and parentheses)
    >                    -     greater than? (vectorises) [1,1,0,0,0,0,0,0,0] / [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0] / [0,0,0,0,0,0,0,0,0,0]
        Œl               -     lower-case                 ["rv (2006)"] / ["ichannel (2006)"] / ["300 (2006)"]
       a                 -     AND (vectorises)           ['r','v',0,0,0,0,0,0,0] / ['i','c','h','a','n','n','e','l',0,0,0,0,0,0,0] / [0,0,0,0,0,0,0,0,0,0]
   ż                     -   zip together                 [["(2006)",'r'],["RV",'v'],[0],[0],[0],[0],[0],[0],[0]] / [["(2006)",'i'],["iChannel",'c'],['h'],['a'],['n'],['n'],['e'],['l'],[0],[0],[0],[0],[0],[0],[0]] / [["(2006)",0],["300",0],[0],[0],[0],[0],[0],[0],[0],[0]]
           Ḣ             -   head                         ["(2006)",'r'] / ["(2006)",'i'] / ["(2006)",0]
            O            -   cast to ordinal (vectorises) [[40,50,48,48,54,41],114] / [[40,50,48,48,54,41],105] / [[40,50,48,48,54,41],0]
                         -   (Jelly cannot compare characters with integers)
              L          -   length                       9 / 15 / 10
             ;           -   concatenate                  [[40,50,48,48,54,41],114,9] / [[40,50,48,48,54,41],105,15] / [[40,50,48,48,54,41],0,10]
                   Ɗ     -   last three links as a monad:
                 i       -     1st index of item in...
                ⁹        -     chain's right argument, X    1 /  2 /  3
                  N      -     negated                     -1 / -2 / -3
               ;         -   concatenate                  [[40,50,48,48,54,41],114,9,-1] / [[40,50,48,48,54,41],105,15,-2] / [[40,50,48,48,54,41],0,10,-3]
                     \   -   cumulative reduce with:
                    ȧ    -     AND (does not vectorise)   [[40,50,48,48,54,41],114,9,-1] / [[40,50,48,48,54,41],105,15,-2] / [[40,50,48,48,54,41],0,0,0]
                         -                           i.e. max / middle / min
                         -                                so the sort, Þ, reverses this input:
                         -                                ["300 (2006)", "iChannel (2006)", "RV (2006)"]
\$\endgroup\$
1
\$\begingroup\$

Perl 6, 58 bytes

*.sort({~m/\(\d+/,/^\d/??(0,$++)!!(1,.uc.ord,.chars,$--)})

Try it online!

\$\endgroup\$
  • \$\begingroup\$ You can use .uc instead of .uc.ord. Also you could use <( to ignore the \( as in / \( <( \d+/ would return 2010 instead of (2010. Since movies have only ever been produced in 4 digit years what you have is shorter and works. \$\endgroup\$ – Brad Gilbert b2gills Mar 20 '18 at 17:42
  • \$\begingroup\$ @BradGilbertb2gills .uc.ord is required to only sort on the first letter. An equally short alternative is m/./.uc. \$\endgroup\$ – nwellnhof Mar 20 '18 at 18:04

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.