# Count Consecutive Characters

Given a string containing only letters, output the length of the longest run of consecutive alphabetical letters the word contains, where order does not matter. An example algorithm may sort the word, remove duplicates, and then output the length of the longest run.

## Test Cases

watch -> 1
stars -> 3
antidisestablishmentarianism -> 3
backdoor -> 4
a -> 1
tutorials -> 4


For example, antidisestablishmentarianism contains the letters abdehilmnstr. The longest runs are lmn and rst, both of length 3.

## Notes

You may take all lowercase, all uppercase, or mixed-case letters as input, but the case cannot encode information about the word (i.e. you cannot make the first n characters capitalized where n is the length of the longest run).

This is , so shortest answer in bytes wins.

• @H.PWiz, I'm guessing that's a typo and it should be rst - uniquify, sort and get longest consecutive run. Can we take input as an array of characters? – Shaggy Jul 11 '18 at 21:46
• @Shaggy yes, definitely, I didn't include it because I thought it was a default – Stephen Jul 11 '18 at 21:51
• Is 'a' adjacent to 'z' -- should 'zebra' score 2 or 3? – Jonathan Allan Jul 11 '18 at 21:54
• (...judging by your example algorithm I guess "no" and "2") – Jonathan Allan Jul 11 '18 at 22:00
• @JonathanAllan you are correct – Stephen Jul 11 '18 at 22:05

# Jelly,  10 9 8 7  6 bytes

OṬṣ0ZL


Try it online!

9 was using Sok's method: ṢQẆẇƇØaṪL

### How?

OṬṣ0ZL - Link: list of (single-case) characters  e.g.  codegolf
O      - ordinal (vectorises)           [99,111,100,101,103,111,108,102]
Ṭ     - untruth (1s at those indices)  [0,0,0,...,1,1,1,1,1,0,0,0,0,1,0,0,1]
-                                 ^         ^       ^         ^     ^
-                   i.e. indices: 1        99     103       108   111
0   - literal zero
ṣ    - split at                       [[],[],[],...,[1,1,1,1,1],[],[],[],[1],[],[1]]
Z  - transpose                      [[1,1,1],[1],[1],[1],[1]]
L - length                         5


# R, 44 43 bytes

Works on an array of lowercase characters. Edit: changed it from testing True values to multiplying by the T/F for a byte.

function(x,r=rle(letters%in%x))max(r$l*r$v)


Try it online!

Does a run length encoding on letters that are in the supplied characters then return the max value for the trues.

• Was working on a similar rle solution using utf8ToInt but taking an array of string is much smarter. +1 – JayCe Jul 12 '18 at 0:12
• @JayCe Started out the same way, but then realised that a letters %in% check took care of the sort, unique and diff steps in one swoop – MickyT Jul 12 '18 at 2:32

# APL (Dyalog Classic), 10 9 bytes

-1 byte thanks to H.PWiz

≢⍉↑⊆⍨⎕a∊⍞


Try it online!

⍞ inputs a string

⎕a is the uppercase English alphabet

⎕a∊⍞ a boolean length-26 vector - which letters occur in the string?

⊆⍨ form vectors of consecutive 1s

≢⍉↑ mix into a matrix, transpose, and return its height - effectively, find the length of the longest vector of 1s

• ⌈/≢¨ -> ≢⍉↑ – H.PWiz Jul 11 '18 at 22:39

# Perl 6, 41 bytes

{max values bag .ords.sort.squish Z-0..*}


Test it

## Expanded:

{  # bare block lambda with implicit param $_ max # find the max values # get the values from the following Bag (repeat counts) bag # find the repeats .ords.sort.squish # get the unique ordinals (method call on$_)
Z-                  # zip subtract with
0 .. *            # Range starting with 0
}


Given 'stars', .ords.sort.squish Z-0..* would return (97,113,113,113)

f[]=0
f s=1+f[c|c<-s,elem(succ c)s]


Try it online!

f s=maximum$scanl(\x c->sum[x+1|elem c s])0['a'..]  Try it online! # JavaScript (Node.js), 51 bytes The case of the input string doesn't matter. s=>(g=_=>s&&1+g(s&=s*2))(Buffer(s).map(c=>s|=1<<c))  Try it online! ### How? We first convert the input string into a bitmask of encountered letters with: Buffer(s).map(c => s |= 1 << c)  The bitwise shift is processed with an implicit modulo 32. Example: "feedback" --> 100001111110 kjihgfedcba-  We then 'reduce' runs of consecutive 1's in the bitmask by repeatedly AND'ing it with a left-shifted copy of itself until all bits are cleared: 0100001111110 AND 1000011111100 --> 0000001111100 0000001111100 AND 0000011111000 --> 0000001111000 0000001111000 AND 0000011110000 --> 0000001110000 0000001110000 AND 0000011100000 --> 0000001100000 0000001100000 AND 0000011000000 --> 0000001000000 0000001000000 AND 0000010000000 --> 0000000000000  The number of consecutive letters in alphabetical order is the number of iterations of the above process. Hence the recursive function: g = _ => s && 1 + g(s &= s * 2)  # Pyth, 9 bytes le}#G.:S{  Input is assumed to be a lower case string. Try it out online here, or verify all the test cases at once here. le}#G.:S{Q Q=eval(input()), G=lowercase alphabet. Trailing Q inferred. {Q Deduplicate input string S Sort it .: Take all substrings (these are generated in length order) }#G Filter out those that aren't found in the alphabet le Find the length of the last remaining element  • Great method using the fact that the substrings are ordered by length! – Jonathan Allan Jul 11 '18 at 22:43 • It'll be much less efficient, but you can use y in place of .:. – FryAmTheEggman Jul 12 '18 at 15:48 # MATL, 10 bytes 2Y2imY'*X>  Input is in lowercase. This uses a mix of @Sundar's (old) and @ngn's approaches. ### Explanation Consider input 'tutorial' as an example. 2Y2 % Push predefind literal 'abcdefghijklmnopqrstuvwxyz' % STACK: 'abcdefghijklmnopqrstuvwxyz' i % Push input % STACK: 'abcdefghijklmnopqrstuvwxyz', 'tutorials' m % Ismember: true for letters present in the input % STACK: [1 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 1 1 1 0 0 0 0 0] Y' % Run-length encoding % STACK: [1 0 1 0 1 0 1 0 1 0], [1 7 1 2 1 2 1 2 4 5] * % Multiply, element-wise % STACK: [1 0 1 0 1 0 1 0 4 0] X> % Maximum. Implicitly display % STACK: 4  # Python 3, 55 bytes f=lambda s:s and-~f({*s}&{chr(ord(c)+1)for c in s})or 0  Try it online! # Python 2, 58 bytes f=lambda s,c=99,r=0:c and max(r,f(s,c-1,-~r*(chr(c)in s)))  Try it online! # Python 2, 63 bytes n=t=0 for c in input():n|=2**ord(c) while n:n&=n/2;t+=1 print t  Try it online! # 05AB1E, 6 bytes Saved 1 byte thanks to Adnan: taking the contiguous substrings, then sorting by length (Œ...é) $\to$ using the powerset built-in instead (æ). êæAÃθg  Try it online! ### Also 6 bytes Saved 2 bytes, again thanks to Adnan: using ASå instead êÇ¥Θ, thus also removing the need to increment the maximum at the end. See the revision history to compare the beviours of the two methods. ASåγOà  Try it online! ### How those works I like challenges like this one which lead to a variety of different approaches. êæAÃθg | Full program. ê | Push a sorted and without duplicates version of the input. æ | Powerser. AÃ | Keep those that also occur in the lowercase alphabet. θg | Take the length of the last one. θ and  can be used interchangeably. -------+------------------------------------------------------------------------------- ASåγOà | Full program. A | Push the lowercase alphabet. S | Listify it (i.e. convert it to a sequence of characters). å | Replace each char in the alphabet by 1 if its in the input, else by 0. γ | Split into chunks of equal adjacent elements. O | Sum each part. à | Extract the maximum of this list. Again, à and Z can be used interchangeably.  • The first program can be golfed to êæAÃg and the second program can be golfed to ASåγOZ. – Adnan Jul 12 '18 at 9:23 • @Adnan Thanks, updated! I like the ASå trick. – Mr. Xcoder Jul 12 '18 at 12:19 # TSQL (Microsoft SQL Server), 206 bytes WITH C AS (SELECT 1p,SUBSTRING(@,1,1)c UNION ALL SELECT p+1,SUBSTRING(@,p+1,1)FROM C WHERE p<LEN(@)),R AS(SELECT c d,1r FROM C UNION ALL SELECT c,r+1FROM R JOIN c ON ASCII(d)+1=ASCII(c))SELECT MAX(r)FROM R  For input, use the following DECLARE statement before the code: DECLARE @ varchar(200) = 'propinquities';  It is expected that input is all the same case (upper or lower doesn't matter, but mixed case would not work). Ungolfed: DECLARE @data varchar(200) = 'propinquities' ;WITH CTE AS ( SELECT 1 as CharacterPosition, SUBSTRING(@data,1,1) as Character UNION ALL SELECT CharacterPosition + 1, SUBSTRING(@data,CharacterPosition + 1,1) FROM CTE WHERE CharacterPosition < LEN(@data) ), Runs AS ( SELECT Character, 1 rc FROM CTE UNION ALL SELECT b.Character, rc + 1 FROM Runs r JOIN CTE b ON ASCII(r.Character) + 1 = ASCII(b.Character) ) SELECT max(rc) from runs  Explanation: Splits the string into a a row for each character (adapted from https://stackoverflow.com/a/27623321/1474939) in the CTE cte. Then, finds runs of consecutive letters by converting to the ASCII code in the Runs cte. Lastly, it picks the largest run and reports back in the select statement. • Good answer, very nice use of the CTE. Not sure if this would help or hurt your byte count, but the "approved" method to get input in T-SQL is via a pre-created table. – BradC Jul 18 '18 at 18:19 • @BradC If I can take a table with each row as one character (sort of like a char array instead of a string), then it would help remove one CTE. If it still has to be one row, it's probably about the same as taking it as an input variable. Thanks for the idea though! – Brian J Jul 18 '18 at 18:59 # C (gcc), 58 56 bytes Saved 2 bytes thanks to @gastropner Uses the same approach as my Node.js answer. The case of the input string doesn't matter. m,i;f(char*s){for(i=0;*s?m|=1<<*s++:(i++,m&=m*2););s=i;}  Try it online! ### Commented m, // m = bitmask of encountered letters i; // i = counter of max. consecutive letters f(char *s) { // f = function taking the input string s for( // main loop: i = 0; // start with i = 0 and assume m = 0 on first call // (it is forced back to 0 when the program terminates) *s ? // if we haven't reached the end of the string: m |= 1 << *s++ // update m by setting the appropriate bit for this character // (with implicit modulo 32) and advance the string pointer : ( // else: i++, // increment i m &= m * 2 // 'reduce' runs of consecutive 1's in m by AND'ing it with a ); // left-shifted copy of itself (e.g. 11101 & 111010 -> 11000; // 11000 & 110000 -> 10000); we stop when m = 0 ); // end of for() s = i; } // return i  • Is it implementation specific that 1<<*s wraps or is it standard behaviour? – Jonathan Frech Jul 12 '18 at 1:40 • @JonathanFrech I think that's officially undefined behavior. So it must be implementation specific. – Arnauld Jul 12 '18 at 1:50 • Because interestingly enough it only appears to wrap when it is computed at runtime. At compile time 1<<32 results in 0 and issues a data type size warning. – Jonathan Frech Jul 12 '18 at 10:48 • Actually, I doubt that the compiler would explicitly apply a 5-bit mask. Chances are that this is done at the CPU level. – Arnauld Jul 12 '18 at 11:02 • @Arnauld it is (see the note: "[...] The count operand can be an immediate value or register CL. The count is masked to 5 bits, which limits the count range to 0 to 31.") – ErikF Jul 12 '18 at 15:30 # C (gcc), 100 bytes c,o,u;n(t,e,r)char*r,*e,*t;{for(u=0,e=t;c=*t++;u=u<o?o:u)for(o=0,r=e;*r;*r++-c||(c++,r=e,++o));o=u;}  Try it online! # Explanation c,o,u;n(t,e,r) // setup, function declaration char*r,*e,*t;{ // K&R style for(u=0,e=t; // initialize global maximum u to 0, write string start to e c=*t++; // look at every character in the string u=u <o?o: u) // funny face for(o=0,r=e;*r; // initialize local maximum o to 0, look at entire string again *r++-c||(c++, // equal character found, search for next one r=e,++o)); // reset local pointer, increment local maximum o=u;} // return maximum character streak  Try it online! • +1 for the "c,o,u;n(t,e,r)" :) – user34409 Jul 12 '18 at 6:29 # MATL, 12 10 bytes 91:wX-dX>q  Try it online! ### Explanation: 91: - Create the list of numbers from 1 to 91. 91 is character '[', which comes after 'Z'. So this effectively creates the list of all characters from '\x1' to '['. (We mainly want those in the range ['A'-1 : 'Z'+1], but having the rest doesn't hurt, and needs less bytecount.) w - Implicit input, bring input to top of stack (assume 'TUTORIALS') X- - Set difference. This leaves only the characters that were not found in the input string, in their original order ('stable'). Stack: ' !"#$%&'()*+,-./0123456789:;<=>?@BCDEFGHJKMNPQVWXYZ['

d - Difference between successive elements in that list. Stack: [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 2 1 2 1 2 1 5 1 1 1 1 1]

X> - Get the maximum of those differences i.e. the max number of consecutive alphabets missing from the set difference.

q - Decrement to get actual character count

Older:

### 12 bytes

Sud1=Y'*X>sQ


Try it online!

• So many approaches :-) – Luis Mendo Jul 12 '18 at 0:49

# K (ngn/k), 17 15 bytes

#1_{x^x^x+1}\-:


Try it online!

- is there only to convert the chars to numbers (it doesn't matter if they are negative)

{ }\ applies a function until convergence, preserving intermediate results

x+1 add 1 to each number in x

^ "without" - the list on the left without elements that occur in the list on the right

x^x^x+1 means x intersected with x+1

1_ drop the first element

# count

• #1_{x^x^x+1}\-? – Adám Jul 11 '18 at 21:47
• @Adám yeah, one day I should make trains work... – ngn Jul 11 '18 at 21:52
• conceptualizing this as the intersection with the increment until convergence is quite nice – Jonah Jul 12 '18 at 1:59
• trains work­­­­ – ngn Dec 8 '19 at 18:07

# Retina 0.8.2, 54 bytes

O.
D.
.
$&$&¶
Tl_l¶.
(.)¶\1
$1 .(.+)$.1
O#^
1G


Try it online! Link includes test cases. Explanation:

O.


Sort the letters into order.

D.


Deduplicate the letters.

.
$&$&¶


Duplicate each letter on separate lines.

Tl_l¶.


Decrement the first of each pair.

(.)¶\1
$1  If this now matches the previous character, join them back together. .(.+)$.1


Count the lengths of all the runs.

O#^


Sort them in reverse numerical order.

1G


Take the first (largest).

# J, 16 bytes

-7 bytes thanks to FrownyFrog

[:>./a.#;._1@e.]


Try it online!

## explanation

[: >./ a. #;._1@e. ]
a. (    )e. ]    is the ascii alphabet an element of the input:
this will transform the alphabet into a 1-0 array,
the ones representing the letters in the input
#;._1@        split that 1-0 list up into pieces, using 0
as the delimiter, and transforming each chunk
into its length. now we have a list of ints
[: >./                  take the max

• I think that you can use ] instead of ~.@/:~ The alphabet is already sorted, so you don't need to sort the input and keep only the unique items. TIO - 18 bytes – Galen Ivanov Jul 12 '18 at 6:21
• 16 – FrownyFrog Jul 12 '18 at 9:52
• @FrownyFrog and Galen, Thank you both! In retrospect it should have been obvious I didn't need that uniq/sort first. – Jonah Jul 12 '18 at 12:56

# C (gcc), 98 92 bytes

Thanks to Jonathan Frech for the suggestions.

Uppercase-only.

f(char*s){int a[99]={0},i,j,k=j=i=0;for(;*s;a[*s++]++);for(;i<99;j=!!a[i++]*++j,k=j>k?j:k);}


Try it online!

• You do not actually need the k; at the end. Implicit gcc returning is a side effect of variable assignment which appearently is executed as a last step in your for loop. – Jonathan Frech Jul 12 '18 at 10:58
• Possible 95 bytes. – Jonathan Frech Jul 12 '18 at 11:00
• @JonathanFrech I don't trust gcc's implicit returns. They don't always happen the way that I expect them to, and they often don't work at all for pointers and floating-point. Fortunately, outside of code golf I never use them! :-) – ErikF Jul 12 '18 at 15:36

# Japt-h, 9 bytes

Case insenstive, takes input as a string or an array of characters.

;CôkU mÊn


Try it or run multiple tests (the second line serves as a replacement for the -h flag so the flag can be used to process multiple inputs instead)

## Explanation

              :Implicit input of string/array U
;C            :The lowercase alphabet
ô           :Partition at characters returning truthy
kU         :  Remove all characters in U from the current letter
:  This will return a non-empty string (truthy) if the current letter ISN'T in U
m        :Map
Ê       :  Length
n      :Sort
:Implicitly output the last element in the array

• @Downvoter, could you provide a reason for your -1, please? – Shaggy Jul 13 '18 at 10:03

## Perl 5, 68 bytes

$"=<>;map{$"=~/$_/i&&++$$_||last for_..z;.=$$_ if$$_>$.}a..z;say$.  Ungolfed: use feature 'say'; my$s = <>;
my $r; for ('a' .. 'z') { my$c = 0;
for ($_ .. 'z') { last if$s !~ /$_/i;$c++;
}
$r =$c if $c >$r;
}
say($r);  # C (gcc), 6665 63 bytes Assumes input only contains lowercase letters. First, it loops over the string and sets bits in an integer according to which letters are seen. Next, it counts the longest streak of 1 bits in the integer. Edit: a is global, so will be initialised to 0 at first call. The second loop makes sure it is reset to 0 before returning. Therefore, we can avoid resetting it manually. a,l;f(char*s){for(l=0;*s;)a|=1<<*s++-97;for(;a;l++)a&=a*2;s=l;}  Try it online! ## Perl 5, 62 + 2 (-nF flag) = 64 bytes $c[ord lc$_]=1for@F;$y[y///c]++for"@c "=~/((1 )+)/g}{say@y/2|0


## Perl 5, 68 bytes

<>=~s/./$c[ord lc$&]=1/gre;\$y[y///c]++for"@c "=~/((1 )+)/g;say@y/2|0

• Nice approach! I'd not considered that method at all... You can save a few bytes using -pF and -MList::Util+(max) to get to 56: Try it online! – Dom Hastings Jul 13 '18 at 9:25
• @DomHastings -MList::Util=max adds 16 bytes to the result score. – Denis Ibaev Jul 13 '18 at 11:32
• If I understand the new scoring correctly, command-line flags aren't counted as bytes, but as as a separately scored language, so rather than just Perl, it'd be Perl with -MList::Util+(max) -pF, or similar. codegolf.meta.stackexchange.com/a/14339/9365 – Dom Hastings Jul 13 '18 at 11:57

# SQLite 265

WITH w AS(SELECT'a'w),n AS(SELECT 1 n UNION ALL SELECT n+1 FROM n LIMIT(SELECT length(w)FROM w)),l AS(SELECT substr(w,n,1)l FROM n,w)SELECT max(v)FROM(SELECT min(n)v FROM(SELECT*FROM l,n EXCEPT SELECT l.l,unicode(l.l)-unicode(b.l)d FROM l,l b WHERE d>0)GROUP BY l);


Ungolfed:

WITH w AS (SELECT 'antidisestablishmentarianism' w)
, n AS (SELECT 1 n
UNION ALL
SELECT n+1 FROM n
LIMIT (SELECT length(w) FROM w) )
, l AS (SELECT DISTINCT substr(w,n,1) l FROM n,w ORDER BY l)
, d AS (
SELECT l,n FROM l,n
EXCEPT
SELECT a.l l, unicode(a.l) - unicode(b.l) d
FROM l a, l b
WHERE d > 0
)

SELECT max(v) FROM ( SELECT min(d.n) v FROM d GROUP BY d.l );


# Brachylog, 1413 12 bytes

{⊇pS∧ẠsSl}ᶠ⌉


Try it online!

{        }ᶠ    % Find all values that satisfy this predicate
⌉   % And get their maximum
% The predicate being:
⊇pS           % There exists a permutation of a subset of the input
%  Call it S
∧          % And,
sS       % S is a substring of
Ạ         %  the set of alphabets, Ạ,
l      % Then, the length of that substring is the return value of the
%  predicate


Slow enough that it doesn't finish for input "antidisestablishmentarianism" on TIO. Relatively much faster one for +1 byte:

### 13 bytes

{dosS∧ẠsSl}ᶠ⌉


Try it online!

Use dos instead of ⊇p: S is a deduplicated sorted substring of the input, instead of just some permutation of some subset.

import Data.List
maximum.map length.filter(isInfixOf['a'..'z']).subsequences.nub.sort


Try it online!

Expects lowercase characters

Explanation:

maximum.map length.filter(isInfixOf['a'..'z']).subsequences.nub.sort
sort {- sort the characters -}
nub      {- remove duplicates -}
subsequences          {- all subsequences -}
filter(isInfixOf['a'..'z'])                       {- all characters are adjacent -}
map length                                                     {- length of filtered subsequences -}
maximum                                                                {- maxmimum length -}


# Python 2, 95 bytes

lambda s:max(reduce(lambda(p,v),c:(c,v+[v[-1]*(c==p+1)+1]),map(ord,sorted(set(s))),(0,[0]))[1])


Try it online!

# Pyth - 11 bytes

le@.:G).:S{


Input must be wrapped in quotes. If not allowed:

# Pyth - 12 bytes

le@.:G).:S{z


Explanation:

l(
e(
@(
.:(G),
.:(
S(
{(Q)
)
)
)
)
)
length(
last element(
intersection(
all positive length substrings(the alphabet as string),
all positive length substrings(
sorted(
uniquified(input)
)
)
)
)
)


# Kotlin, 97 bytes

{w:String->{var s=0
var m=0
for(c in 'a'..'z')if(c in w)s++
else{if(s>m)m=s
s=0}
if(s>m)m=s
m}()}


Try it online!

# Java 8, 77 bytes

int i,j,m;
c->{for(i=j=0;(m=j<c.length?m|1<<c[j++]:m&m*2+0*++i)>0;);return i;}


Port of Arnauld's C answer. Try it online here.

Ungolfed:

int i, j, m; // instance variables of the surrounding class - initialised to 0
c -> { // lambda - c is of type char[]; return type is int
for(i = j = 0; // i is the length of the longest run, j is used to step through c - both start at 0
(m = j < c.length // work with the bitmask of all the letters present in c: if we have not reached the end of c ...
? m | 1 << c[j++] // ... set the bit corresponding to the current character, advance one character ...
: m & m * 2 + 0 * ++i) > 0 ;) ; // ... else reduce runs of consecutively set bits in m by AND-combining it with a left-shifted copy of itself until m hits 0
return i; // return the result - by now m is back to 0
}


# ><>, 63 bytes

Reads lowercase characters from stdin, outputs a number to stdout.

0l55*)?\
8/?(0:i<]r1~r[-*c
~/00
}</?)@:{:*+1/?(3l
\~:03. ;n~/


Try it online!

0l55*)?\             Push 26 zeroes onto the stack

Record which characters are used
i              Read a character from the input
/?(0:               Check if it is -1, marking the end of the input
8             -*c    Subtract 96 from the character code,
giving 1 for 'a', 2 for 'b' etc.
r[       Pop that many values on to a new stack and reverse
it, putting that character's value at the top of
the stack
1~         Write 1 to that value
]r           Return the stack back to it's normal state

Count the longest run of ones in the stack
00                 Push values for currentRun = 0, and bestRun = 0
}                    Move bestRun to the bottom of the stack
/?(3l    Check if there are only 2 values left on the stack
+1         Increment currentRun
*           Multiply currentRun by the next value in the stack,
resetting it to 0 if the run is broken
/?)@:{:            Check if currentRun > bestRun
\~:                Overwrite bestRun if so
03.             Jump back to the start of loop
;n~/        Once all values have been consumed,
print bestRun and exit