15
\$\begingroup\$

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 determine1 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.

1 Accuracy not guaranteed. No refunds.

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

20 Answers 20

12
\$\begingroup\$

05AB1E, 3 bytes

é.M

Input as a list of lines.

Try it online or verify all test cases.

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)
answered Jan 9, 2023 at 8:20
\$\endgroup\$
11
\$\begingroup\$

Vyxal, 4 bytes

Þṡ∆M

Try it Online!

Þṡ # Sort by length
 ∆M # Get the most common item (order overrides repetitions)
answered Jan 9, 2023 at 5:14
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Defeating the creator :) \$\endgroup\$ Commented Jan 9, 2023 at 5:52
  • \$\begingroup\$ Cool that Vyxal sort of has a builtin for this. Nice solution \$\endgroup\$ Commented Jan 9, 2023 at 15:37
10
\$\begingroup\$

Excel (ms365), 74 bytes

enter image description here

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.
answered Jan 9, 2023 at 13:40
\$\endgroup\$
2
  • \$\begingroup\$ I think the result should only be love me do. \$\endgroup\$ Commented Jan 9, 2023 at 14:37
  • \$\begingroup\$ The result should be "Love, love me do" \$\endgroup\$ Commented Jan 9, 2023 at 15:32
8
\$\begingroup\$

Python, (削除) 49 (削除ここまで) 43 bytes

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

Attempt This Online!

Takes input as a list of lines

answered Jan 9, 2023 at 9:08
\$\endgroup\$
0
6
\$\begingroup\$

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│
    └────────────┘
    
answered Jan 9, 2023 at 3:27
\$\endgroup\$
6
  • \$\begingroup\$ J always seems very intimidating to me because of its syntax. I’d be interested to know how this solution works. \$\endgroup\$ Commented Jan 9, 2023 at 3:38
  • 1
    \$\begingroup\$ @Jacob I updated the solution but added an explanation to the new one. \$\endgroup\$ Commented Jan 9, 2023 at 4:40
  • 1
    \$\begingroup\$ Why do you need multiplying input length if len(line) is encoded after decimal point? \$\endgroup\$ Commented Jan 9, 2023 at 5:28
  • \$\begingroup\$ tio.run/##7VPfa9RAEH7PX/… \$\endgroup\$ Commented Jan 9, 2023 at 5:44
  • \$\begingroup\$ I removed some input line in tio link for lack of space, but you shouldn't \$\endgroup\$ Commented Jan 9, 2023 at 5:50
5
\$\begingroup\$

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>

answered Jan 9, 2023 at 2:32
\$\endgroup\$
1
  • \$\begingroup\$ Nice solution! Didn’t think of doing it this way \$\endgroup\$ Commented Jan 9, 2023 at 3:35
5
\$\begingroup\$

PARI/GP, 38 bytes

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

Attempt This Online!

Based on @l4m2's JavaScript answer.

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.

answered Jan 9, 2023 at 3:19
\$\endgroup\$
5
\$\begingroup\$

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 '

answered Jan 9, 2023 at 6:08
\$\endgroup\$
4
\$\begingroup\$

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

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
answered Jan 9, 2023 at 2:25
\$\endgroup\$
3
\$\begingroup\$

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.

answered Jan 9, 2023 at 10:25
\$\endgroup\$
2
\$\begingroup\$

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!

answered Jan 9, 2023 at 16:34
\$\endgroup\$
2
\$\begingroup\$

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.
answered Jan 9, 2023 at 5:13
\$\endgroup\$
2
\$\begingroup\$

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.

answered Jan 9, 2023 at 18:56
\$\endgroup\$
2
\$\begingroup\$

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!

answered Jan 10, 2023 at 19:06
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 23 bytes

WS⊞υι≔Eυ⟦Noυι±Lι⟧θ§υ⌕θ⌈θ

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.

WS⊞υι

Input the lines of the song.

≔Eυ⟦Noυι±Lι⟧θ

Get the count and negated length of each line.

§υ⌕θ⌈θ

Output the line that has the maximum value of that.

answered Jan 10, 2023 at 22:53
\$\endgroup\$
1
\$\begingroup\$

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
answered Jan 11, 2023 at 18:39
\$\endgroup\$
1
\$\begingroup\$

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
answered Mar 10, 2023 at 4:43
\$\endgroup\$
1
\$\begingroup\$

Nekomata, 4 bytes

ŢṂaş

Attempt This Online!

ŢṂ Maximum by count
 aş Minimum by length
answered Jul 10, 2023 at 6:10
\$\endgroup\$
0
\$\begingroup\$

Mathematica, 59 bytes

Try it online!

f@a_:=Commonest[Select[a,Length[#]==Max[Length/@a]&]][[1]];
answered Jul 10, 2023 at 7:57
\$\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.