# Longest run of a character in a string

Your challenge: Write a function that takes a string s, a character c, and finds the length of the longest run of c in s. The length of the run will be l.

Rules:

• If s is of length 0 or c is empty, l should be 0.
• If there are no instances of c in s, l should be 0.
• Standard loopholes and Standard I/O Rules apply.
• No matter where in s the run of cs is located, l should be the same.
• Any printable ASCII characters can appear in s and c.

Test cases:

s,c --> l
"Hello, World!",'l'  -->  2
"Foobar",'o'         -->  2
"abcdef",'e'         -->  1
"three   spaces",' ' -->  3
"xxx xxxx xx",'x'    -->  4
"xxxx xx xxx",'x'    -->  4
"",'a'               -->  0
"anything",''        -->  0


Winner:

As with the shortest answer in each language wins.

• – MD XF Jun 8 '17 at 18:01
• Could you include the edge cases of empty s and a c that isn't contained in a non-empty s in your test cases? – Martin Ender Jun 8 '17 at 18:22
• What range of characters can appear in s/c? – Martin Ender Jun 8 '17 at 18:23
• c can be empty? In many languages, a character is just an integer with special semantics, and you can't really have an empty integer either. – Martin Ender Jun 8 '17 at 18:40
• That doesn't really make sense to me. Your test cases suggest that we have to support it. If we don't have to support it, then specifying its required output doesn't make sense, because I can always just say that it's not supported if my solution would do something else in that case. – Martin Ender Jun 8 '17 at 18:45

# 05AB1E, 5 bytes

### Code:

SQγOM


Uses the 05AB1E encoding. Try it online!

### Explanation:

SQ      # Check for each character if it is equal to the second input
γ     # Split the list of zeros and ones into groups
O    # Sum each array in the arrays
M   # Get the maximum

• Nice solution! I knew there was a way to do it like this, I just couldn't think of it. – Riley Jun 8 '17 at 18:22
• γ¢M isn't performing like I thought it would, thought that'd be a 3-byte. – Magic Octopus Urn Jun 8 '17 at 19:31

# Mathematica, 35 bytes

Max[Tr/@Split@Boole@Thread[#==#2]]&


Pure function taking a list of characters and another character as input and returning a nonnegative integer. Improved upon my first effort using Adnan's observation (go upvote!) that one should test for equaling the special character before splitting the array.

Thread[#==#2] checks whether each input character in the first argument equals the character given as the second argument. Boole converts the resulting Trues and Falses to 1s and 0s. Split splits the list into runs of consecutive elements; Tr/@ sums each sublist, and Max finds the winner. (Because of how Max works, if the first argument is the empty list, then this function returns -∞. So, you know, don't do that.)

## first submission (51 bytes)

Max[Split@#/.a:{c_String..}:>Boole[c==#2]Length@a]&


Split@# splits the input into runs of consecutive characters, such as {{"t"}, {"h"}, {"r"}, {"e", "e"}, {" ", " ", " "}, {"s"}, {"p"}, {"a"}, {"c"}, {"e"}, {"s"}} for the fourth test case. /.a:{c_String..}:> replaces each subexpression a that is a list of a repeated character c by Length@a multiplied by Boole[c==#2], which is 1 if c equals the input character and 0 otherwise. Then Max extracts the answer.

# Japt, 20 18 15 bytes

fV+Vî+)ª0)n o l


Try it online!

Saved 5 bytes thanks to obarakon and ETHproductions

• I played around with my own solution for a while and ended up with one that was nearly yours, but shorter. If you use fV+Vî+)... I'll let you figure the rest out :-) – ETHproductions Jun 8 '17 at 20:03
• @ETHproductions "If s is of length 0 or c is empty, l should be 0", I might be taking that too literally though – Tom Jun 9 '17 at 11:51
• Oh, I hadn't realized that fails whenever s does not contain any instances of c. – ETHproductions Jun 9 '17 at 11:53

# Python, 38 bytes

f=lambda s,c:+(c in s)and-~f(s,c+c[0])


Try it online!

Dennis saved 3 bytes by updating c to a string of duplicated characters rather than recursively updating a number to multiply c by.

• f=lambda s,c:c in s and-~f(s,c+c[0]) saves 6 bytes (3 if False is not allowed). – Dennis Jun 9 '17 at 7:21

# 05AB1E, 11 6 bytes

-5 bytes thanks to carusocomputing

γvy²¢M


Try it online!

γ      # split into chunks of consecutive equal elements
vy    # For each chunk...
²¢  #  Count the number of input characters in this chunk
M #  Push the largest count so far

• γvy²¢M for 6-bytes, same idea. – Magic Octopus Urn Jun 8 '17 at 19:37

## Haskell, 43 39 bytes

f c=maximum.scanl(\n k->sum[n+1|c==k])0


Try it online!

Run through the string and replace the current char with a counter that is increased whenever it equals c or reset to 0 if not. Take the maximum of the list.

Thanks to @xnor for 4 bytes.

• You can do sum[n+1|c==k]. – xnor Jun 8 '17 at 19:59
• @xnor: Nice! I've experimented with *fromEnum(c==k), both pointfree and lambda, but it was always 2 or 3 bytes longer. – nimi Jun 8 '17 at 20:07

# C# 116 115 bytes

My first code golf

Edited because initial submission was a snippet and was missing required namespace for regex

Edit#2 complete rewrite to support characters with special regex meanings

using System.Linq;s=>c=>System.Text.RegularExpressions.Regex.Replace(s,"[^"+c+"]",++c+"").Split(c).Max(x=>x.Length);

using System.Linq;s=>c=>{var r=(char)(c-1);return string.Join("",s.Select(x=>x==c?c:r)).Split(r).Max(x=>x.Length)};

• I don't know C# but it looks like your code expects variables c and s to be predefined. We call this a "code-snippet" and it is not allowed. You could probably restructure your code as an anonymous function or to set those variables to input. Both of which are allowed. – Wheat Wizard Jun 8 '17 at 19:09
• Does that work? (See above edit) – Broom Jun 8 '17 at 19:29
• Once again I don't know C#, but it looks like it does. You might want to checkout our tips for golfing in C# here for more experienced advice in C#. – Wheat Wizard Jun 8 '17 at 19:33
• Thanks for the links! I will definitely peruse the C# tips – Broom Jun 8 '17 at 19:38
• Hi just some general comments for golfing in C#, you can define your function as (s,c)=>. You have to either use System.Text.RegularExpressions.Regex or add an using statement right before your function. – LiefdeWen Jun 9 '17 at 7:47

# JavaScript (ES6), 5453 51 bytes

-2 bytes thanks to @Neil
-1 byte thanks to @apsillers

s=>c=>[...s].map(x=>j=(i=x==c&&i+1)>j?i:j,i=j=0)&&j


Takes input in currying syntax: f("foobar")("o").

## Test Snippet

f=
s=>c=>[...s].map(x=>j=(i=x==c&&i+1)>j?i:j,i=j=0)&&j
String: <input id=I> Letter: <input id=J maxlength=1 size=1> <button onclick='O.innerHTML+=f("${I.value}")("${J.value}") = ${f(I.value)(J.value)}\n'>Run</button><pre id="O"></pre> ### Another option using eval and for (54 bytes) s=>c=>eval("i=j=0;for(x of s)i=x==c&&i+1,i>j?j=i:0;j")  ### Old Answer using Regex (85 bytes) s=>c=>c?Math.max(...s.match(eval(/${/\w/.test(c)?c:"\\"+c}*/g)).map(x=>x.length)):0

• I think x==c?i++:i=0 can just be i=x==c&&i+1 since a false result on x==c comparison will be treated as a 0 for numerical comparisons and increments (and will never be the return value, since any number, including 0, in j will always take priority over the zero-like false in i) – apsillers Jun 8 '17 at 21:05
• @apsillers Thanks, updated, but what do you mean about it never being the return value? – Justin Mariner Jun 8 '17 at 21:19
• Sorry for the confusion; I was just explaining that the change would never make your program return false (since the challenge always requires it to return a number) – apsillers Jun 9 '17 at 12:21
• s=>c=>[...s].map(x=>j=(x!=c?i=0:++i)>j?i:j,i=j=0)&&j seems to save a couple of bytes. – Neil Jun 30 '17 at 21:17
• Sorry, I posted the wrong code, I meant to post f=s=>c=>[...s].map(x=>j=(i=x==c&&i+1)>j?i:j,i=j=0)&&j, which is a byte shorter. – Neil Jun 30 '17 at 22:52

## JavaScript (Firefox 30-57), 75 72 bytes

(s,c)=>Math.max(0,...(for(s of s.split(/((.)\2*)/))if(s[0]==c)s.length))


ES6 compatible snippet:

f=
(s,c)=>Math.max(0,...s.split(/((.)\2*)/).filter(s=>s[0]==c).map(s=>s.length))
<div oninput=o.textContent=f(s.value,c.value)><input id=s><input id=c maxlength=1 size=1><pre id=o>0

split returns a bunch of empty strings and single characters as well as the runs but this doesn't affect the result.

# Micro, 112 bytes

{T l m 1+:Q # T Q T l~:r}:Z{T[0]+}:X
{i s m:n
n p = if(Z,X)
i L=if(,a)}:a
0\\:C:s:i"":p"":n[0]:T
s l:L
a
T l m:\


# C (gcc), 63 bytes

i;m;f(s,c)char*s;{for(i=m=0;*s;s++)*s^c?m=m>i?m:i,i=0:i++;s=m;}


Try it online!

# Perl 6,  45 43  42 bytes

->$_,$c {$c&&$_??.comb(/$c+/)».chars.max!!0}  Test it ->$_,$c {$c&&$_??.comb(/$c+/).max.chars!!0}


Test it

->$_,$c {$c&$_??.comb(/$c+/).max.chars!!0}  Test it ## Expanded: ->$_, $c { # pointy block lambda$c & $_ # AND junction of$c and $_ # empty$c would run forever
#   empty $_ would return 4 ( "-Inf".chars ) ?? # if True (neither are empty) .comb(/$c+/)  # find all the substrings
.max          # find the max
.chars        # get the length

!!              # if False (either is empty)

0             # return 0
}


# JavaScript, ES6, 52

Recursive solution that treats the string input as an array (note: the initial input is still a string) and consumes left-to-right in character C:

f=([C,...s],c,t=0,T=0)=>C?f(s,c,C==c&&++t,t>T?t:T):T


Tracks current run in t and global best in T.

Explanation:

f=            // function is stored in f (for recursion)
([C,...s],  // turn input string in first-char C and the rest in s
c,         // argument c to search for
t=0,T=0)   // current total t, best total T
=>
C?             // if there is still any char left in the string
f(s,c,       // recursively call f
C==c&&++t, // increment t if char is match, or set t to false
t>T?t:T)   // set global T to max of t and T
:T           // when string is depleted, return T


Setting t to false on non-matches works because whenever t is incremented, false is treated as 0 (i.e., false + 1 is 1), and false will never compare grater than any value in global-max T.

• Nice solution, I was unfamiliar with the [C,...s] syntax. Should help me slice() off bytes from my own posts. – Rick Hitchcock Jun 9 '17 at 11:16

# Jelly, 5 bytes

=ŒgṀS


This is a dyadic link/function that takes a string and a character. Note that it cannot work as a full program, as input from command-line arguments uses Python syntax, and Python – unlike Jelly – does not distinguish singleton strings from characters.

Try it online!

### How it works

=ŒgṀS  Main link. Left argument: s (string). Right argument: c (character)

=      Compare all characters in s with c, yielding 1 for c and 0 otherwise.
Œg    Group adjacent, equal Booleans in the resulting array.
Ṁ   Take the maximum. Note that any array of 1's will be greater than any array
of 0's, while two arrays of the same Booleans are compared by length.
S  Take the sum, yielding the length for an array of 1's and 0 otherwise.


# Retina, 25 bytes

(.).*?(\1*)(?!.+\2).*
$.2  Try it online! The first character is the character to be checked. # APL (Dyalog), 18 11 bytes Requires swapping ⊂ with ⊆ in Version 16.0 or having ⎕ML←3 (default on many systems). ⌈/0,≢¨⊂⍨⎕=⎕  Try it online! ⎕=⎕ Boolean for equality between two inputs ⊂⍨ self-partition (begin partitions where a non-zero element is greater than its predecessor) ≢¨ tally each 0, prepend a zero (for the empty-input cases) ⌈/ max of those Old solution Prompts first for s, then for c ⌈/0,(⎕,¨'+')⎕S 1⊢⎕  Try it online! ⎕ prompt for s ⊢ for that ()⎕S 1 PCRE Search for the lengths of occurrences of '+' a plus symbol (meaning one or more) ,¨ appended to each of the elements of ⎕ the prompted-for c 0, prepend a zero (for the empty-input cases) ⌈/ max of those c must be given as a 1-element vector of an enclosed string if it needs escaping. # PHP, 70 67 bytes three versions: while(~$c=$argv[1][$i++])$x=max($x,$n=($c==$argv[2])*++$n);echo+$x; while(~$c=$argv[1][$i++])$x=max($x,$n=$c==$argv[2]?++$n:0);echo+$x; for(;++$n&&~$c=$argv[1][$i++];)$x=max($x,$n*=$c==$argv[2]);echo+$x;  takes input from command line arguments; run with -r or test them online. # PHP, 70 bytes for(;~$c=$argv[1][$i++];)$r[]=$argv[2]==$c?++$n:$n=0;echo$r?max($r):0;  Try it online! # PHP, 75 bytes for(;~$s=substr($argv[1],$i++);)$r[]=strspn($s,$argv[2]);echo max($r?:[0]);


Try it online!

# PHP, 83 bytes

<?=@preg_match_all("<".preg_quote($argv[2])."+>",$argv[1],$t)?strlen(max($t[0])):0;


Try it online!

+8 Bytes to avoid @

<?=($a=$argv[2])&&preg_match_all("<".preg_quote($a)."+>",$argv[1],$t)?strlen(max($t[0])):0;

• The 67 bytes version will fail for any regex special char (and # of course). – Titus Jun 9 '17 at 9:46
• ... and ~ may fail for chr(207). – Titus Jun 9 '17 at 9:49
• @Titus Done and Input can only be Ascii characters – Jörg Hülsermann Jun 9 '17 at 10:15
• good eye for ++$n! You meant printable ascii. ;) – Titus Jun 10 '17 at 5:43 • echo$r?max($r):0; saves one byte – Titus Jun 10 '17 at 5:57 # JavaScript (ES6), 4740 38 bytes (Saved 7 bytes thanks to @Neil, and 2 bytes thanks to @HermanLauenstein.) s=>g=c=>c&&s.includes(c)?1+g(c+c[0]):0  Explanation: Recursively searches for a longer run until none is found. Snippet: let f= s=>g=c=>c&&s.includes(c)?1+g(c+c[0]):0 console.log(f('Hello, World!')('l' )); //2 console.log(f('Foobar')('o' )); //2 console.log(f('abcdef')('e' )); //1 console.log(f('three spaces')(' ' )); //3 console.log(f('xxx xxxx xx')('x' )); //4 console.log(f('xxxx xx xxx')('x' )); //4 console.log(f('')('a' )); //0 console.log(f('anything')('' )); //0 • So simple! Brilliant! – apsillers Jun 8 '17 at 23:37 • Can you not do f=(s,c)=>c&&s.includes(c)&&1+f(s,c+c[0])? – Neil Jun 30 '17 at 21:21 • Or better still, curry it to s=>g=c=>c&&s.includes(c)&&1+g(c+c[0]). – Neil Jun 30 '17 at 21:24 • That almost works, but it returns "false" and a null string for the last two cases. That's fixed by appending ||0, which is still shorter than my solution. – Rick Hitchcock Jun 30 '17 at 21:27 • The f= isn't part of the curried version, because only the inner function is recursive. – Neil Jun 30 '17 at 22:58 # Jelly, 10 9 bytes f⁴L ŒgÇ€Ṁ  Explanation: f⁴L f⁴ -Filter by the character argument. L -Return Length of filtered String. ŒgÇ€»/ Œg -Group string by runs of characters. Ç€ -Run above function on each group. Ṁ -Return the largest in the list.  Try it online! • You can save a couple of bytes with Œgf€L€Ṁ. – Dennis Jun 9 '17 at 7:13 # Python 3, 71 bytes f=lambda s,c,m=0,k=0:s and f(s[1:],c,-~m*(s[0]==c),max(m,k))or max(m,k)  Try it online! # Haskell, 66 bytes import Data.List ((maximum.(0:).map length).).(.group).filter.elem  Try it online! A slightly easier to read version - not pointfree: f c s = maximum (0:(map length (filter (elem c) (group s))))  Groups the string by letter, then filters by those groups that contain the right character, then finds the lengths, appends 0 to the list of lengths in case it doesn't appear, and finally finds the maximum value. # Mathematica, 109 bytes (s=Differences[First/@StringPosition[#,#2]];k=t=0;Table[If[s[[i]]==1,t++;If[k<t,k=t],t=0],{i,Length@s}];k+1)&  input ["xxx xxxx xx","x"] # Python 2, 69 bytes lambda s,c:c and max(map(len,re.findall(c+'+',s))or[0])or 0 import re  Try it online! # CJam, 201918 16 bytes 0q~ef{~@=*}$+W=


Try it online!

### Explanation

0                 e# Push 0. We'll need it later.
q~               e# Read and eval input. Pushes c and s to the stack.
e             e# Run-length encode s: turns it into an array of [length, char] pairs.
f{           e# Map over these pairs using c an extra parameter:
~          e#  Dump the pair to the stack.
@=        e#  Bring c to the top, check equality with the char, pushing 0 or 1.
*       e#  Multiply the length by the result.
}      e# (end map)
$e# Sort the resulting list in ascending order. + e# Prepend the 0 from before, in case it's empty. W= e# Get the last element.  # Excel, 56 bytes {=MAX(IFERROR(FIND(REPT(A2,ROW(A:A)),A1)^0*ROW(A:A),0))}  s should be input to A1. c should be input to A2. Formula must be an array formula (Ctrl+Shift+Enter) which adds curly brackets { }. Technically, this can only handle where the longest run is less than 1,048,576 (which is 2^20) because that's how rows the current Excel will let you have in a worksheet. Since it loads the million+ values into memory whenever it recalculates, this is not a fast formula. # MATL, 15 bytes 0i0v=dfd1L)0hX>  Try it online! The basic algorithm is very simple (no use of split!), but I had to throw in 0i0v and 0h to allow for the edge cases. Still, I thought the approach was nice, and perhaps I can still find another technique to handle the edge cases: the algorithm finds the longest run in the middle of a string just fine, but not for single characters or empty strings; I'm still testing if I can 'pad' the variables at better places for better results. 0i0v % Prepends and appends a zero to the (implicit) input. = % Element-wise equality with the desired char (implicit input) d % Pairwise difference. Results in a 1 at the start of a run, and -1 at the end. f % Get indices of 1's and -1's. d % Difference to get length of the runs (as well as length of non-runs) 1L) % Only select runs, throw out non-runs. We now have an array of all run lengths. 0h % 'Find' (f) returns empty if no run is found, so append a zero to the previous array. X> % Maximum value.  Does not work on empty c. Then again, I suppose each string contains an infinite run of empty strings between each character :) # R, 66 58 bytes -8 bytes thanks to BLT and MickyT function(s,c)max((r=rle(el(strsplit(s,''))))$l*(r$v==c),0)  returns an anonymous function. TIO has a 1-byte difference because el doesn't work there for inexplicable reasons. Try it online! • Save a byte with r=rle(el(strsplit(s,''))) – BLT Jun 8 '17 at 21:26 • Ignore my previous comment if you saw it. Got a better one for you function(s,c)max((r=rle(el(strsplit(s,''))))$l*(r\$v==c),0) – MickyT Jun 8 '17 at 21:44
• @BLT el doesn't work on TIO (no idea why) and I just copied and pasted it from the working code there so I'll have to remember to put that back in @MickyT very clever! Thanks! – Giuseppe Jun 9 '17 at 14:03

# Java 8, 67 65 bytes

s->c->{int t=0,m=0;for(char x:s)m=m>(t=x==c?t+1:0)?m:t;return m;}


-2 bytes thanks to @OlivierGrégoire

Takes input s as a char[], and c as a char

Explanation:

Try it here.

s->c->{          // Method with char[] and char parameters and int return-type
int t=0,       //  Temp counter-integer
m=0;       //  Max integer
for(char a:s)  //  Loop over the characters of the input
m=m>(
t=x==c?     //   If the current character equals the input-character:
t+1        //    Raise t by 1
:          //   Else:
0)        //    Reset t to 0
?m:t;        //   If t is now larger than m, put t as new max into m
//  End of loop (implicit / single-line body)
return m;      //  Return the resulting max
}                // End of method

• m=m>(t=x==c?t+1:0)?m:t; is shorter than {t=x==c?t+1:0;m=m>t?m:t;}. – Olivier Grégoire Jun 9 '17 at 15:34
• Even though it's wayyyyyy longer, I like my first thought: s->c->java.util.Arrays.stream(s.split("[^"+c+"]")).mapToInt(z->z.length()).max().orElse(0) ;) – Olivier Grégoire Jun 9 '17 at 15:48

# Ruby, 40 bytes

->s,c{s.split(%r{[^#{c}]}).max&.size||0}

Try it online!