# Guess the song title

I have this problem where I listen to so much music that I can never remember what songs are called. But even if I remember the lyrics, I won't always know the song's name. But lucky for me, there's a pretty neat formula to determine¹ the title of a song just based on its lyrics.

I'll define the way a song title can be guessed as the line repeated in its lyrics the most times. If multiple lines are repeated the same number of times, choose the shortest of them. If multiple lyrics both occur the same number of times and are of equal length, you may choose any of them.

Given an input of a multiline string where each line is a lyric (you may take input as a list of lines), output the predicted title of the song, using the method outlined above.

For example, say this totally real song was stuck in my head and I couldn't remember its name:

Hello, world
Hello, world
I just got to say it, hello world
Goodbye, world
Goodbye, world
Goodbye


I can figure using this formula that the song's title is "Hello, world".

You may assume that the input string will contain no empty lines.

## Test cases:

Links go to pastebins of the lyrics, with any " removed.

This is , so shortest code in bytes wins.

¹ Accuracy not guaranteed. No refunds.

• It turns out you only get 1/4 correct rate on test cases :)
– l4m2
Jan 9, 2023 at 2:27
• What if there is a tie in length as well as count? Jan 9, 2023 at 2:36
• @chunes In that case you may choose any of the tied lyrics. Jan 9, 2023 at 3:30
• @KevinCruijssen Depending on where you put your line breaks, I'd say that song should just be called "Hey now"... Jan 9, 2023 at 15:30

# 05AB1E, 3 bytes

é.M


Input as a list of lines.

Explanation:

é    # Sort the (implicit) input-list by their length (shortest to longest)
.M  # Pop and leave the (first/shortest) most frequent line
# (which is output implicitly as result)


# Vyxal, 4 bytes

Þṡ∆M


Try it Online!

Þṡ   # Sort by length
∆M # Get the most common item (order overrides repetitions)

• Defeating the creator :) Jan 9, 2023 at 5:52
• Cool that Vyxal sort of has a builtin for this. Nice solution Jan 9, 2023 at 15:37

# Excel (ms365), 74 bytes

Formula in B1:

=LET(x,TEXTSPLIT(A1," "),@SORTBY(x,MAP(x,LAMBDA(y,SUM(-(x=y)))),,LEN(x),))

• TEXTSPLIT(A1," ") - Split input in an horizontal array called 'x';
• SORTBY(x,MAP(x,LAMBDA(y,SUM(-(x=y)))),,LEN(x),) - 1st Sort by count, then by length (both ascending by default);
• @ - Use implicit intersection to only return the 1st element in the resulting array.
• I think the result should only be love me do.
– jdt
Jan 9, 2023 at 14:37
• The result should be “Love, love me do” Jan 9, 2023 at 15:32

# Python, 49 43 bytes

lambda a:max(sorted(a,key=len),key=a.count)


Attempt This Online!

Takes input as a list of lines

# J, 28 17 bytes

{.@\:%@#&>+1#.=/~


Try it online!

-11 thanks to l4m2's idea. Also thanks to l4m2 for pointing out an improvement!

Consider:

Hello, world
Hello, world
I just got to say it, hello world
Goodbye, world
Goodbye, world
Goodbye


In J we take the input as a list of boxed strings:

┌────────────┬────────────┬─────────────────────────────────┬──────────────┬──────────────┬───────┐
│Hello, world│Hello, world│I just got to say it, hello world│Goodbye, world│Goodbye, world│Goodbye│
└────────────┴────────────┴─────────────────────────────────┴──────────────┴──────────────┴───────┘

• =/~ Create an equality table to see which lines equal other lines:

1 1 0 0 0 0
1 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 1 0
0 0 0 1 1 0
0 0 0 0 0 1

• 1#. Sum the rows (resulting length is now equal to input length):

2 2 1 2 2 1

• %@#&>+ And add the reciprocals of each line length elementwise:

2.083 2.083 1.0303 2.071 2.071 1.1429

• {.@\: Use that result to sort the input descending, and take the first:

┌────────────┐
│Hello, world│
└────────────┘

• J always seems very intimidating to me because of its syntax. I’d be interested to know how this solution works. Jan 9, 2023 at 3:38
• @Jacob I updated the solution but added an explanation to the new one. Jan 9, 2023 at 4:40
• Why do you need multiplying input length if len(line) is encoded after decimal point?
– l4m2
Jan 9, 2023 at 5:28
• tio.run/##7VPfa9RAEH7PX/…
– l4m2
Jan 9, 2023 at 5:44
• I removed some input line in tio link for lack of space, but you shouldn't
– l4m2
Jan 9, 2023 at 5:50

# JavaScript (Node.js), 65 61 bytes

x=>x.sort(g=(a,b)=>a?(x.map(b=>b!=a?x:0)+a).length-g(b):0)[0]


Try it online!

Sort <different lines>*(<input length>-1)+<element length>

• Nice solution! Didn’t think of doing it this way Jan 9, 2023 at 3:35

# PARI/GP, 38 bytes

s->vecsort(s,a->[[1|l<-s,a!=l],#a])[1]


Attempt This Online!

Takes a list of lines.

# PARI/GP, 46 bytes

s->vecsort(matreduce(s)~,a->#a[1]*I-a[2])[1,1]


Attempt This Online!

Takes a list of lines.

# Jelly, 6 bytes

Æṃ'LÞḢ


Try it online!

For some reason, Jelly's mode atom insists on vectorising over a list of lines, so we need '

# Japt-g, 9 bytes

Input as an array of lines.

ü üÊÌcÌñÊ


Try it

ü üÊÌcÌñÊ     :Implicit input of array
ü             :Group & sort by value
ü           :Group & sort by
Ê          :  Length
Ì         :Last element
c        :Flat map
Ì       :  Last element
ñ      :Sort by
Ê     :  Length
:Implicit output of first element

• Love it! Beats my initial solution ü üÊo mÎñÊ -g (10 bytes) which is pretty close to your 9-byte version. Jan 9, 2023 at 11:44
• Nice work, @Jacob; you seem to be getting to grips with Japt nicely. Jan 9, 2023 at 19:22
• Just came back to this, it seems that your 8-byte version is failing test cases. Jan 12, 2023 at 22:44
• Fails for "All Star" and "Hello world" Jan 12, 2023 at 22:46
• Thanks, @Jacob. I actually realised that the other night down the pub but forgot to update the next morn'. Will do so tomorrow. Jan 12, 2023 at 23:36

# Vyxal, 11 7 bytes

vOÞMİÞg


Try it Online!

## Explained

vOÞMİÞg
vO       # [input.count(item) for item in input]
ÞM     # indices of maximal items
İ    # indexed into the input
Þg  # shortest by length


# Retina 0.8.2, 40 bytes

O
O^$#$.&
O^$#(.+¶)(?=(\1)*)$#2
1G


Try it online! Takes input as a list of newline-terminated strings. Explanation:

O


Sort everything.

O^$#$.&


Sort order of length, then reverse the result. The reverse in the next sort will then bring the shortest line of equal occurrence count back to the front.

O^$#(.+¶)(?=(\1)*)$#2


Sort by count of subsequent occurrences. Only one of each of the most frequent lines will actually sort last, but that doesn't matter because we only need one of them. The sort is stable, so the most frequent lines remain sorted in descending order of length. The result is then reversed, bringing the shortest most frequent line to the start.

1G


Keep only the first line.

# Scala 3, 40 bytes

s=>s.maxBy(l=>(s.count(Set(l)),-l.size))


Returns a tuple from the comparison key, which are ordered lexicographically.

Attempt This Online!

# Factor,  62 61  60 bytes

[ [ length ] sort-with dup histogram '[ _ at ] supremum-by ]


Try it online!

• [ length ] sort-with Sort by ascending length.
• dup histogram '[ _ at ] supremum-by Find the most frequent element that is encountered first.

# PowerShell, 49 bytes

($input|group|sort C*,{-$_.Name.Length})[-1].Name


Try it online!

Input comes from the pipeline.

$input is an automatic variable that enumerates all input that is piped to a function. The lines are passed to the cmdlet Group-Object which groups identical lines into GroupInfo objects with the properties Count and Name (the original line). The objects are then sorted first by the Count property (how often a line was found), and then the negative (so both Count and Length can be sorted ascending) length of the line. Then the last element of the sorted array [-1] is taken, and its Name property returned. Output is implicit. Will return "Woah, love me do" (same length as "Love, love me do") for the Beatles because of the ascending sorting. # Go, 140 bytes import."strings" func f(s string)(O string){m,M:=-1,make(map[string]int) for _,l:=range Split(s,"\n"){if M[l]+=1;M[l]>m{O,m=l,M[l]}} return}  Attempt This Online! # Charcoal, 23 bytes ＷＳ⊞υι≔Ｅυ⟦№υι±Ｌι⟧θ§υ⌕θ⌈θ  Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated strings. Explanation: Port of @mousetail's original Python answer. ＷＳ⊞υι  Input the lines of the song. ≔Ｅυ⟦№υι±Ｌι⟧θ  Get the count and negated length of each line. §υ⌕θ⌈θ  Output the line that has the maximum value of that. # Pip-r, 15 bytes @Y-(_Ng)AE#_SKg  The -r flag reads the program arguments from lines of stdin rather than command-line args. Attempt This Online! ### Explanation @Y-(_Ng)AE#_SKg g ; Lines of stdin (due to -r flag) SK ; Sort ascending according to this key function: _Ng ; Number of occurrences of this line in the input list -( ) ; Negated AE ; Placed in a list with #_ ; Length of the line Y ; No-op, necessary for parsing @ ; Get the first element of the sorted list  # Arturo, 41 bytes $[a][minimum arrange a=>size=>[size--a&]]


Try it

\$[a][                     ; a function taking an argument a
minimum               ; get minimum element of
arrange a=>size       ; input sorted by ascending length
=>[                   ; by
size              ; length of
--                ; set difference between
a                 ; input
&                 ; current line
]                     ; end minimum
]                         ; end function


# Nekomata, 4 bytes

ŢṂaş


Attempt This Online!

ŢṂ      Maximum by count
aş    Minimum by length


# Mathematica, 59 bytes

Try it online!

f@a_:=Commonest[Select[a,Length[#]==Max[Length/@a]&]][[1]];