# Mode length of a sentence

The task is simple. You are given a string with alphabetical words (say "Hello world, this are tests"). You have to return the mode of the lengths of words in the string. In this case, output is 5, as it's the most often length of words in the string.

Definition of an alphabetical word (for this challenge): a string that consists of a-zA-Z only.

### Sample I/O:

Constraints: Input has atleast one word, and a unique mode. Max. length is provided in last test case. Also, the string would be a single line, no newline chars.

(In = Out format)

"Hello world, this are tests"                     =  5
"Hello    world, this... are tests"               =  5
"I"                                               =  1
"Let's box (ง︡'-'︠)ง"                               =  3
"Writing some ✍(◔◡◔) program"                   =  7
"the-the-the-then"                                =  3
"Gooooooooogle is an app"                         =  2
"()<>a+/sentence$#@(@with::many---_symbols{}|~~" = 4 "anot_her test actually" = 4  The unicode tests are optional. 1000 words string = 5 (Password: PXuCdMj5u65vwst) This is a , so fewest bytes will win! • I don't understand the "hidden test" - who are you hiding it from? Why isn't the answer for it included in the question? Aug 9 '20 at 15:57 • Why does not the regex for alphanumeric words accept numbers? Aug 9 '20 at 16:13 • @mypronounismonicareinstate, the alphanumeric was a typo, edited it. Aug 9 '20 at 17:08 • Do we really need to handle Unicode chars? It doesn't seem to add anything to the challenge, and it leaves some languages out Aug 9 '20 at 20:03 • @LuisMendo, made them optional now. Aug 10 '20 at 2:07 ## 21 Answers # 05AB1E, 109 7 bytes -1 byte inspired by Jonathan Allans Jelly answer. -2 bytes thanks to Kevin Cruijssen! Input is a list of characters. aγO0K.M  Try it online! ### Commented: aγO0K.M implicit input ["a","b"," ","c","d"," ","e","."] a is_alpha (vectorizes)[1, 1, 0, 0, 1, 1, 0, 1, 0] γ split into chunks of equal elements [[1, 1], [0, 0], [1, 1], [0], [1], [0]] O sum the lists [2, 0, 2, 0, 1, 0] 0K remove 0's .M mode 2 implicit output 2  a is implemented as Regex.match?(~r/^[a-zA-Z]+$/, to_string(x)), which should be equivalent to the challenge specification.

I feel like there has to be a shorter way to remove 0s from a list than ʒĀ}.

• There indeed is a shorter way to remove 0s: 0K. ;) Also, you can save 1 more byte by taking the input as a list of characters, so the € isn't necessary anymore. Aug 20 '20 at 8:25
• @KevinCruijssen thanks a lot. I searched the wiki for remove, delete and filter, but without didn't cross my mind.
– ovs
Aug 20 '20 at 11:00
• Yeah, the descriptions of the builtins are sometimes a bit counter-intuitive to search for unfortunately. :/ I had the same issue for the longest time at first. Luckily I now know almost all builtins out of the top of my head, give or take a few, since I golf so much in 05AB1E. Aug 20 '20 at 12:09

# APL (Dyalog Unicode), 30 bytes

{⍵[⊃⍒+/∘.=⍨⍵]}≢¨⊆⍨⎕A∊⍨1(819⌶)⎕


Try it online!

{⍵[⊃⍒+/∘.=⍨⍵]}≢¨⊆⍨⎕A∊⍨1(819⌶)⎕ ⍝ Full program
1(819⌶)⎕ ⍝ Uppercase the input
⎕A∊⍨     ⍝ Test if each character is a capital letter
⊆⍨       ⍝ Group the letters together
≢¨       ⍝ Length of each word
{⍵[⊃⍒+/∘.=⍨⍵]} ⍝ Mode


The mode dfn is by ngn. My approach was similar but one byte longer: {⊃⍵[⍒+/¨⍵⍷¨⊂⍵]}.

• You can replace (819⌶) with ⎕C in 18.0, though TIO isn't updated yet. Aug 10 '20 at 3:49

# Ruby, 7068 58 bytes

->s{(s=s.scan(/[a-z]+/i).map &:size).max_by{|y|s.count y}}


Try it online!

-20 bytes from Dingus.

-2 bytes from Rahul Verma.

-10 bytes from Dingus(again) by removing a variable.

# Ruby, 90 bytes

->a{a.split(/\W+/).map(&:size).inject(Hash.new(0)){|h,v|h[v]+=1;h}.sort_by{|k,v|v}[-1][0]}


Try it online!

• Ah, you made a separate range. Nice. Aug 10 '20 at 2:15
• -2 bytes, used scan. Aug 10 '20 at 4:27
• Squeezed off another 6 bytes Aug 10 '20 at 5:47
• 58 bytes by squeezing another 4 bytes off Rahul Verma's latest version. Sep 4 '20 at 1:57
• nice golf. I'll put it in. Sep 4 '20 at 2:35

# R, 79 67 bytes

Edit: -9 and then -3 more bytes thanks to Giuseppe

names(sort(-table(nchar(el(strsplit(scan(,''),"[^a-zA-Z]+"))))))[1]


Try it online!

Commented:

names(              # Get the names (=values) of...
sort(-            # the descending (-) frequencies of...
table(          # the table of values of...
(w=nchar(      # the number of characters of...
strsplit(scan(,''),
# the input, grouped by splitting on...
"[^a-zA-Z0-9]")[[1]]))
# non-alphanumeric characters...
[w>0]          # ignoring zero-length groups.
)
)
)[1]                # Output the first name, which is
# the most-frequent number of characters
# per group.

• 70 bytes; it's a shame that "\\W+" wouldn't work since it includes _ Aug 10 '20 at 17:06
• actually, is the 0-9 needed since a word consists only of [a-zA-Z]+? Aug 10 '20 at 17:18
• 1) Thanks! I obviously need a bit of practice at regexes! Aug 10 '20 at 17:29
• 2) Not any more. The question originally specified 'alphanumeric', but I notice that it's now been edited to 'alphabetic' so you're right. Aug 10 '20 at 17:29

# JavaScript (ES6), 66 bytes

s=>s.replace(o=/[a-z]+/gi,w=>o[s]>(o[n=w.length]=-~o[n])?0:s=n)&&s


Try it online!

# Retina 0.8.2, 43 bytes

M!i[a-z]+
%M.
O#
O#^$(.+)(¶\1)*$#2
1G


Try it online! Link includes test cases. Explanation:

M!i[a-z]+


List only the words.

%M.


Take the length of each word.

O#


Sort the lengths numerically.

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


Sort in reverse order of frequency.

1G


Take the mode.

# Jelly, 11 bytes

e€ØẠŒg§ḟ0Æṃ


A monadic Link accepting a list of characters which yields an integer.

Try it online! Or see the test-suite.

### How?

e€ØẠŒg§ḟ0Æṃ - Link: S
ØẠ        - alphabetic characters
€          - for each (c in S)
e           -   (c) exists in (S)?
Œg      - group runs of equal elements (1s or 0s)
§     - sums
0   - zero
ḟ    - filter discard
Æṃ - mode


# Perl 5-pF'[^A-Za-z]+', 51 bytes

map$k{y///c}++,@F;$_=(sort{$k{$b}-$k{$a}}keys%k)[0]


Try it online!

• Nice, just made pretty much the same too! You can shave a few bytes using %; as the name of the hash, using for instead of map...,... and using ($_)=<list> Try it online! Aug 10 '20 at 20:00 • Also, not that it matters, but I think \Pl should be equivalent to [^A-Za-z]> Aug 10 '20 at 20:03 # MATL, 8 bytes 3Y4XXzXM  Supports ASCII characters only. Try it online! Or verify all ASCII test cases. ### How it works 3Y4 % Push predefined literal '[A-Za-z]+' XX % Implicit input. Regexp. Gives cell array of matched substrings z % Number of nonzero chars of each substring XM % Mode. Implicit display  # Pip, 18 bytes aMR:+XA#_(_NaSKav)  Try it online! ### Explanation aMR:+XA#_(_NaSKav) a is 1st cmdline arg; v is -1 (implicit) aMR: Map a function to each regex match in a and assign the result back to a +XA Regex: a letter (XA) repeated one or more times (+) #_ The function: length of the match Now we just need to get the mode: SKa Sort a using this key function: _Na Count of each element in the full list a ( v) Since it's now sorted from least common to most, get the last element  If Pip had a two-byte builtin for getting the mode of a list, I could do this in 10 bytes: MO#*Ya@+XA (with MO being the mode builtin). Ah well. # Python 3, 148143140132100 99 bytes n,*c=0, for x in input()+'1': if''<x.lower()<'{':n+=1 elif n:c+=n,;n=0 print(max(c,key=c.count))  Try it online! Uses regex to check if character is a letter of the English alphabet and adds the count of all consecutive alphabets to a list and finds the mode of that list. -3 bytes thanks to Rahul Verma -32 bytes thanks to ovs -1 byte thanks to DLosc • Also, you could just write import re and re.match. Result: -3 bytes. Aug 10 '20 at 5:52 • @DLosc isalpha() returns True for some non-English characters as well. Check out the 4th example. Aug 10 '20 at 7:05 • you can create lists with [*...], the re.match can be replaced by ''<s.pop(0).lower()<'{' and appending to a list is shorter with +=: Try it online! – ovs Aug 10 '20 at 10:20 • And a for-loop is more fitting here: Try it online! – ovs Aug 10 '20 at 10:23 • Hm. I was going by "The unicode tests are optional," but fair enough. In any case, you can save 1 more byte using this tip: change the first line to n,*c=0, Aug 11 '20 at 1:04 # Husk, 12 8 bytes ►=mLmf√w  Try it online! Previous answer was badly optimized.(-4 bytes) From Zgarb: ► has a second mode. If you give it a binary function f, it returns an element x that maximizes the number of elements y for which fxy holds. So ►= is a 2-byte max by frequency. ## Explanation ►=fImLmf√ġK√ ġK√ group string on non alphabet-characters. f√ filter out non-alphabet characters m map that to each word ↑ mL Length of each word fI filter out zeroes (empty string length) ►= max by frequency  # Scala, 66 bytes "[a-zA-Z]+".r.findAllIn(_).toSeq.groupBy(_.size)maxBy(_._2.size)_1  Try it in Scastie Unfortunately, finding the mode in Scala is a bit clumsy # Io, 141 bytes A really awful solution... just 2 bytes shorter than the Python one. 3 method(x,x asUppercase asList map(i,if(if(i at(0),i at(0),0)isLetter,1,0))join split("0")map(size)remove(0)uniqueCount map(reverse)max at(1))  Try it online! # Java (JDK), 129 bytes Saved 10 bytes thanks to @ceilingcat! s->{int m=0,z=s.length()+1,a[]=new int[z];for(var x:s.split("[^a-zA-Z]+"))a[x.length()]++;for(;z-->0;m=a[z]>a[m]?z:m);return m;};  Try it online! Explanation: s -> { int m=0, //m is the index of the max element in a z=s.length()+1, //z is to avoid using a.length twice a[]=new int[z]; //Each index corresponds to a length, and the element at that index its frequency for(var x : s.split("[^a-zA-Z]+")) //Fill up the pigeonholes a[x.length()]++; for(; //Find the index of the max element/highest frequency/mode z-->0; //For every index from a.length to 0, m=a[z]>a[m]?z:m); //If the current element is greater than the current max frequency, change the mode length return m; //Return the length with the highest frequency };  • 115 bytes Aug 10 '20 at 15:51 • @OlivierGrégoire That's a really cool approach! Do you want to make your own answer? – rues Aug 10 '20 at 19:47 • Indeed, the approach is different, so I understand you don't want to use it as your own. I've posted it as my own answer. Aug 10 '20 at 21:02 # Java (JDK), 113 bytes s->{int m=0,l=s.length(),t,L=0;for(;l>0;L=t>m?(m=t)-m+l:L)t=s.split("\\b[a-zA-Z]{"+l--+"}\\b").length;return-~L;}  Try it online! ## Explanation This basically splits the String on ascii words of all possible lengths to count them, and returns the max value of the count. s->{ int m=0, // The maximum number of l=s.length(), // The length of ASCII letters, going from high to low t, // Declare a temp variable. L=0; // Initialize the most present length to 0. for( // Loop ; l>0; // On each length, going down L=t>m?(m=t)-m+l:L // If a count is higher than the max count, the new count becomes the max count and the most present length becomes the current length ) t= s.split("\\b[a-zA-Z]{"+l--+"}\\b") // Count the number of parts between or around words of length l // Also, decrement l .length; // Store the count into t return-~L; // Return L + 1 }  # C (gcc), 115113 112 bytes -1 byte ceilingcat m;n;w;c;l;i;f(char*s){for(m=n=l=0;s[l++];m=c>n?n=c,l:m)for(i=w=c=0;w=isalpha(s[i])?1+w:w-l?0:!++c,s[i++];);n=m;}  Try it online! # Japt v2.0a0, 13 bytes q\L f üÊñÊÌÌÊ  Try it q\L f üÊñÊÌÌÊ :Implicit input of string U e.g., "()<>a+/sentence$#@(@with::many---_symbols{}|~~"
q                 :Split on
\L               :  Regex /[^a-z]/i             ["","","","","a","","sentence","","","","","with","","many","","","","symbols","","","","",""]
f             :Filter (remove empty strings) ["a","sentence","with","many","symbols"]
ü           :Group & sort by
Ê          :  Length                      [["a"],["with","many"],["symbols"],["sentence"]]
ñ         :Sort by
Ê        :  Length                      [["a"],["symbols"],["sentence"],["with","many"]]
Ì       :Last element                  ["with","many"]
Ì      :Last element                  "many"
Ê     :Length                        4


# Python 3.8, 81 75 bytes

Thanks to Mukundan314 for 5 bytes and ovs for another 1 byte

lambda S:max(L:=[*map(len,re.findall("[a-z]+",S,2))],key=L.count)
import re


Try it online!

Anonymous function: Finds all runs of letters using regex, collects a list of the lengths of those runs, and prints the item with the maximum frequency in the list.

• -5 bytes by using python 3.8's assignment expr Aug 10 '20 at 5:16
• You can use re.findall('[a-z]+",input(),2) for -1. (2 is the value of the re.IGNORECASE flag)
– ovs
Aug 10 '20 at 10:40

# Wolfram Language (Mathematica), 48 bytes

Commonest@*StringLength@*StringCases[__?LetterQ]


Try it online! Function. Takes a string as input and returns a list of most common lengths as output. The list should only have a single number if the mode length is unique. It gives incorrect output on one of the Unicode examples, presumably due to ง counting as a letter.

# PHP, 101 bytes

$a=array_count_values(array_map(strlen,preg_split('/[^A-Za-z]/',$argn,0,1)));arsort($a);echo key($a);


Try it online!

Drat PHP and it's super long function names again...