Write a function or program that accepts a list of boolean values and returns all of the ranges of True's.

Test Cases:

f [F]                               = []
f [T]                               = [[0,0]]
f [T,T,F,T]                         = [[0,1],[3,3]]
f [F,T,T,F,F,T,T,T]                 = [[1,2],[5,7]]
f [F,T,T,F,F,F,T,T,T,T]             = [[1,2],[6,9]]
f [T,T,F,F,F,T,T,T,T,T,T,T,T,T,T,F] = [[0,1],[5,14]]
f [F,F,T,T,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T] = [[2,3],[12,19],[33,54],[93,94]]


  • You may choose how input is encoded, e.g. a list, array, string, etc.
  • The output must be encoded as a list-like of list-likes or a string showing such, so arrays, lists, tuples, matrices, vectors, etc.
  • The boolean values must be encoded as constants, but otherwise any simple conversion of T/F to desired constants is allowed
  • EDIT: eval or similar during runtime IS allowed.
  • Don't to forget to explain how input is passed to the program/function and give its input/output for the test cases
  • Conversion to desired input format not counted
  • Standard loopholes are disallowed
  • If your language has a function to do this, it's not allowed
  • I will not accept my own submission
  • EDIT: Output format is flexible. If not printing a list or similar, range values must be separated by one non-numeric character and separate ranges as well.


  • Score is in bytes, unless unfit to your language (such as codels in Piet)
  • Lowest score wins

There's a good bit of flexibility in input and output, but solutions where T/F are replaced with functions that do all the work are disallowed.


If you write yours in Haskell or can call it from Haskell, the following will check your function/program:

import Test.QuickCheck

tf = cycle [True,False]
gen l = foldl (++) [] $ map (\i -> [tf!!i | x<-[1..i]]) l
putIn (a,b) l = zipWith (||) l [(a <= p) && (p <= b) | p <- [0..length l]]
putAllIn rs len = foldr putIn [False|i<-[1..len]] rs
main = print $ quickCheck (check functionNameGoesHere)
  • 1
    \$\begingroup\$ I may be missing something, but I don't see a description of how a range is represented in the output. \$\endgroup\$ Commented Jan 11, 2016 at 18:53
  • 1
    \$\begingroup\$ Can the output be 1-indexed? \$\endgroup\$ Commented Jan 11, 2016 at 22:59
  • \$\begingroup\$ Can the ranges be half-exclusive? \$\endgroup\$
    – lirtosiast
    Commented Jan 12, 2016 at 0:58
  • 1
    \$\begingroup\$ @LegionMammal978 Only if your language default is 1-indexed, for example Mathematica \$\endgroup\$ Commented Jan 12, 2016 at 1:00
  • \$\begingroup\$ @ThomasKwa Nope, that seems too different for "edge" cases \$\endgroup\$ Commented Jan 12, 2016 at 1:03

37 Answers 37


Pyth, 18 bytes


Test suite

True is represented as 1, False as 0.

Ranges are represented inclusively.

  • \$\begingroup\$ Can you add an explanation? \$\endgroup\$
    – lirtosiast
    Commented Jan 12, 2016 at 22:47
  • \$\begingroup\$ Sure, sometime else. \$\endgroup\$
    – isaacg
    Commented Jan 12, 2016 at 22:49
  • 2
    \$\begingroup\$ spoiler alert - it's been 5 years and he never posted it \$\endgroup\$ Commented May 11, 2021 at 14:17

Pyth, 17 16 bytes


Uses some fancy post-assign counter magic together with run length encoding.

Takes input as an array of 0s and 1s, e.g. [1, 1, 0, 1, 0]. Outputs like in the challenge, e.g. [[0, 1], [3, 3]].

Test Suite

  • \$\begingroup\$ I added a test suite. If the edit is approved and no one snipes, you have the shortest valid answer. \$\endgroup\$ Commented Jan 14, 2016 at 19:42

Retina, 82 34 27 bytes



The empty line should contain a single space.

Input is a flat string of _ for true and : for false. Output is space-separated pairs, each on a separate line.

Try it online.


The heavy golfing from 82 down to 27 bytes was possible by clever choice of the representation of true and false. I've picked a word character, _, (that isn't a digit) for true and a non-word character, :, (that doesn't need escaping) for false. That allows me to detect the ends of ranges as word boundaries.


We match a word boundary. We want to replace that boundary with the corresponding index of the truthy value. In principle that is quite easy with Retina's recent $# feature, which counts the number of captures of a group. We simply capture each character in front of that position into a group. By counting those characters we get the position. The only catch is that the ends of the range are off by one now. We actually want the index of the character in front the match. That is also easily fixed by optionally matching a _ which isn't captured, thereby skipping one character when we're at the end of a range.


Now we replace all runs of underscores with a space. That is, we insert a space between the beginning and end of each range, while getting rid of the underscores.


That leaves the colons (and we still need to separate pairs). We do that by splitting the entire string into lines around each colon. The S actives split mode, and the _ suppresses empty segments such that don't get tons of empty lines when we have runs of colons.


Python 2, 69 bytes

for x in input()+[0]:
 if x-p:b=x<p;print`i-b`+';'*b,

Example output:

2 3; 7 16; 18 18;

A direct approach, no built-ins. Tracks the current value x and the previous value p. When these are different, we've switched runs. On switching 0 to 1, prints the current index i. On switching 1 to 0, prints the current index minus one followed by a semicolon.

The if is pretty smelly. Maybe recursion would be better,


MATL, 17 18 20 bytes


Uses current version (9.1.0) of the language/compiler.

Input is a string containing characters T and F. Output is a two-row table, where each column indicates a range using 1-indexing, which is the language default.

Thanks to Stewie Griffin for removing 2 bytes.


>> matl
 > j'T+'1X32X34$2#XX
2 7
3 10


It's based on a simple regular expression:

j         % input string
'T+'      % regular expression: match one or more `T` in a row
1X3       % predefined string literal: 'start'
2X3       % predefined string literal: 'end'
4$2#XX    % regexp with 4 inputs (all the above) and 2 outputs (start and end indices)
          % implicitly display start and end indices

Octave, 43 Bytes


find(diff([0,x,0])) finds all the positions where the input array changes between true and false. By reshaping this into a 2-by-n matrix we achieve two things: The changes from true to false, and from false to true are divided into two rows. This makes it possible to subtract 1 and 2 from each of those rows. Subtracting 1 from row one is necessary because Octave is 1-indexed, not zero-indexed. Subtracting 2 from row two is necessary because the find(diff()) finds the position of the first false value, while we want the last true value. The subtraction part is only possible in Octave, not in MATLAB.


ans =    
    2   12   33   93
    3   19   54   94

ans =    
    0    5
    1   14
  • 1
    \$\begingroup\$ Nice use of broadcasting! \$\endgroup\$
    – Luis Mendo
    Commented Jan 11, 2016 at 22:18

CJam, 27 25 bytes


Expects input like TTFTFT. Try it online.


0                               Push 0, to kick off index
qe`                             Push input and run length encode
                                e.g. FFFFTTTFT -> [[4 'F] [3 'T] [1 'F] [1 'T]]
{                 }/            For each pair in the RLE...
 ~                                Unwrap the pair
  ~                               Evaluate T -> 0 (falsy), F -> 15 (truthy)
   { }{         }?                 Ternary based on T/F
    +                                If 'F: add count to index
       1$+:X(]pX                     If 'T: output inclusive range, updating index
;                               Discard the remaining index at the top of the stack

Japt, 34 31 25 bytes

Trying a new approach really worked out this time.


Try it online!

Input is an string with F for false and T for true. Output is an array of arrays; the string representation makes it look like a single array.

How it works

          // Implicit: U = input string
V=[]      // Set V to an empty array. (Why don't I have a variable pre-defined to this? :P)
Ur"T+"    // Take each group of one or more "T"s in the input,
@         // and map each matched string X and its index Y to:
Vp[       //  Push the following to an array in V:
Y         //   Y,
Y-1+Xl    //   Y - 1 + X.length.
]};       //  This pushes the inclusive start and end of the string to V.
V         // Implicit: output last expression

Note: I now see that several people had already come up with this algorithm, but I discovered it independently.

Non-competing version, 22 bytes


In the latest GitHub commit, I've added a new feature: a leading ; sets the variables A-J,L to different values. A is set to an empty array, thus eliminating the need to create it manually.


Vyxal, 12 11 bytes


Try it Online!

Translation of my Jelly answer.


0J             Append 0
  0p          Prepend 0
    ¯         Deltas
     T        Truthy indices
      ⁽ ẇ     Apply to even indices
       ‹        Decrement
         2ẇ   Split into chunks of 2

-1 byte thanks to lyxal

  • \$\begingroup\$ Try it Online! for 11 bytes \$\endgroup\$
    – lyxal
    Commented May 15, 2021 at 13:11
  • \$\begingroup\$ @lyxal Thanks! For some reason I didn't find p when searching for "prepend". \$\endgroup\$
    – xigoi
    Commented May 15, 2021 at 13:55

Haskell, 74 bytes

import Data.Lists
map(\l->(fst$l!!0,fst$last l)).wordsBy(not.snd).zip[0..]

Usage example: map(\l->(fst$l!!0,fst$last l)).wordsBy(not.snd).zip[0..] $ [True,False,True,True,False] -> [(0,0),(2,3)].

How it works:

                               -- example input: [True,False,True,True,False]

zip[0..]                       -- pair each element of the input with it's index
                               -- -> [(0,True),(1,False),(2,True),(3,True),(4,False)]
wordsBy(not.snd)               -- split at "False" values into a list of lists
                               -- -> [[(0,True)],[(2,True),(3,True)]]
map                            -- for every element of this list
   (\l->(fst$l!!0,fst$last l)) -- take the first element of the first pair and the
                               -- first element of the last pair
                               -- -> [(0,0),(2,3)]

J, 26 bytes


This is an unnamed monadic verb (unary function) that returns a 2D array or integers. It is used as follows.

  f =: [:I.&.|:3(<`[/,]`>/)\0,,&0
  f 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0
0  1
5 14


                       ,&0  Append 0 to input
                     0,     then prepend 0.
        3(         )\       For each 3-element sublist (a b c):
               ]`>/           Compute b>c
          <`[/                Compute a<b
              ,               Concatenate them
                            Now we have a 2D array with 1's on left (right) column
                            indicating starts (ends) or 1-runs.
[:I.&.|:                    Transpose, get indices of 1's on each row, transpose back.

Ruby, 39


Sample invocation:

2.2.3 :266 > f=->s{s.scan(/T+/){p$`.size..s=~/.#$'$/}}
 => #<Proc:0x007fe8c5b4a2e8@(irb):266 (lambda)> 
2.2.3 :267 > f["TTFTTFTTTFT"]

The .. is how Ruby represents inclusive ranges.

The one interesting thing here is how I get the index of the end of the range. It's weird. I dynamically create a regular expression that matches the last character of the range, and then all subsequent characters and the end of the string in order to force the correct match. Then I use =~ to get the index of that regex in the original string.

Suspect there might be a shorter way to do this in Ruby using the -naF flags.


Jelly, 12 11 10 bytes


Try it online!

Accepts a list of zeros and ones. Outputs a list of 1-based ranges.


Using [1,1,0,1] as an example.

;0ŻIT’Ðes2   Main monadic link
;0           Append a zero: [1,1,0,1,0]
  Ż          Prepend a zero: [0,1,1,0,1,0]
   I         Increments: [1,0,-1,1,-1]
    T        Indices of truthy alements: [1,3,4,5]
      Ðe     Apply to even indices:
     ’         Decrement: [1,2,4,4]
        s2   Split into groups of two: [[1,2],[4,4]]

JavaScript (ES6), 59

An anonymous function, input as a string of T and F, returning output as an array of arrays







<pre id=O></pre>

  • \$\begingroup\$ Wow, I just came up with the same solution in Japt and was about to translate it to JS. Nice one :) \$\endgroup\$ Commented Jan 12, 2016 at 3:05

𝔼𝕊𝕄𝕚𝕟, 18 chars / 28 bytes


Try it here (Firefox only).


ïħ`T+`,↪ᵖ[_,$Ꝉ+‡_] // implicit: ï=input
ïħ`T+`,            // for each T-sequence...
       ↪ᵖ[_,$Ꝉ+‡_] // push [start index of sequence, end index of sequence] to the stack
                   // implicit stack output

Haskell, 62 bytes

f l|s<-zip3[0..](0:l)$l++[0]=zip[i|(i,0,1)<-s][i-1|(i,1,0)<-s]

Takes as input a list of 0's and 1's.

Given the list l, pads it with 0 on both sides and computes the indexed list of consecutive pairs. For example

l = [1,1,0]
s = [(0,0,1),(1,1,1),(2,1,0),(3,0,0)]

Then, extract the indices corresponding to consecutive elements (0,1) and (1,0), which are the starts of blocks of 0 and 1, subtracting 1 from the starts of 0 to get the ends of 1, and zips the results.

  • \$\begingroup\$ Wow, that bends syntax more than I thought Haskell would take. Is it equivalent to "f l=let s=zip3[0..](0:l)(l++[0]) in zip[i|(i,0,1)<-s][i-1|(i,1,0)<-s]"? \$\endgroup\$ Commented Jan 12, 2016 at 5:02
  • 1
    \$\begingroup\$ @MichaelKlein Yes, I learned of the trick of binding in guards from nimi here. It's also equivalent to the longer binding-via-lambda f l=(\s->zip[i|(i,0,1)<-s][i-1|(i,1,0)<-s])$zip3[0..](0:l)$l++[0]. \$\endgroup\$
    – xnor
    Commented Jan 12, 2016 at 5:05

Pyth, 19 18 bytes



             implicit: Q=input
m            map lambda d:
  -V         Vectorized subtraction by [0,1]
c            split every 2 elements
  x            find all indexes of
    1          1s
    aV         in vectorized xor:
       +ZQ     Q with a 0 on the front
       +QZ     Q with a 0 on the end

Try it here.


Perl, 47 bytes


With the following perlrun options -lpe:

$ perl -lpe's/F*(T*)(T)F*/[$-[0],$+[1]],/g;chop$_;$_="[$_]"' <<< 'TTFFFTTTTTTTTTTF'

Alternative where output is line separated (34 bytes):

$ perl -pE's/F*(T*)(T)F*/$-[0] $+[1]\n/g;chomp' <<< TTFFFTTTTTTTTTTF
0 1
5 15

APL, 17 chars


In ⎕IO←0 and ⎕ML←3. In English:

  • ⍵×⍳⍴⍵: zero out the elements of the index vector as long as the argument where the argument is false
  • ⍵⊂: cut at the beginning of each run of truths and throw away the false's
  • (↑,↑∘⊖)¨: take the first and last element of each subarray

Python 2, 108 bytes

for i,j in enumerate(l):s=j*~k*i or s;~j*l[i-1]and o.append([s,i-1]);k=j
print o

Test cases:

$ python2 rangesinlists2.py
$ python2 rangesinlists2.py
[[0, 0]]
$ python2 rangesinlists2.py
[[0, 1], [3, 3]]
$ python2 rangesinlists2.py
[[1, 2], [5, 7]]
$ python2 rangesinlists2.py
[[1, 2], [6, 9]]
$ python2 rangesinlists2.py
[[0, 1], [5, 14]]
$ python2 rangesinlists2.py
[[2, 3], [12, 19], [33, 54], [93, 94]]

Surely there's a shorter solution than this, but it works.


Haskell: 123 bytes (Example, cannot win)

f l=[(s,e)|let m=length l-1,let r=[0..m],s<-r,e<-r,and[l!!x|x<-[s..e]],s<=e,let(#)p=not$l!!p,s==0||(#)(s-1),e==m||(#)(e+1)]

Less golfed:

f l = [(start,end) | start <- [0..max], end <- [0..max], allTrue start end, start <= end, notBelow start, notAbove end]
    max = (length l) - 1
    allTrue s e = and (subList s e)
    subList s e = [l !! i | i <- [s,e]]
    notBelow  s = (s == 0) || (not (l !! (s-1)))
    notAbove  e = (s == m) || (not (l !! (e+1)))
  • \$\begingroup\$ Even when not golfing: allTrue s e = and (subList s e) or maybe allTrue = (and.) . sublist. \$\endgroup\$
    – nimi
    Commented Jan 11, 2016 at 21:55
  • \$\begingroup\$ Ok, for a reason I don't remember, I thought that was more "clear" when I was ungolfing... (Edited) \$\endgroup\$ Commented Jan 11, 2016 at 21:59
  • 1
    \$\begingroup\$ Oh, sure, opinions differ on what's "clear". I also think all (==True) (subList s e) is very clear. \$\endgroup\$
    – nimi
    Commented Jan 11, 2016 at 22:05

CJam, 30 bytes


Input as a CJam-style array of 0s and 1s. Output as a CJam-style array of pairs.

Run all test cases. (Takes care of the conversion of the input formats.)


Japt, 27 bytes

A=[];Ur"T+"@Ap[YXl +´Y]};A·

There has to be a way to golf this down...

Anyway, it's the same as my 𝔼𝕊𝕄𝕚𝕟 answer.

  • \$\begingroup\$ Wow, I just came up with this solution myself.... Nice algorithm! \$\endgroup\$ Commented Jan 12, 2016 at 3:07

Husk, 14 bytes


Try it online!


K (oK), 19 bytes


Try it online!

Uses -n': (window) so the inner {y&!x,z} function has access to the previous (x), current (y), and next (z) value in the input boolean list.


Jelly, 13 bytes


Try it online!

+4 bytes to handle the all 0s test cases. Without that, a much cleaner 9 bytes. This uses 1 indexing, which is Jelly's default.

How it works

TI’kƊ.ịⱮ$ḢẠ?U - Main link
T             - Indices of truthy elements
    Ɗ         - Group the previous links into a monad f(T):
 I            -   Increments
  ’           -   Decrement
   k          -   Partition T at truthy indexes in the decremented increments

                This returns [[]] for [0] (and repeats) and
                [[a, b], [c, d, e], ...] for every other input

           ?  - If:
          Ạ   -   Condition: All truthy?
        $     -   If:
       Ɱ      -     For each partition:
     .ị       -       Take the 0.5th element
         Ḣ    -   Else: Return []

                For non-integer left argument, x, Jelly's ị atom takes
                floor(x) and ceil(x) and returns [floor(x)ịy, ceil(x)ịy]
                As Jelly's indexing is 1-based and modular:
                  0ị returns the last element
                  1ị returns the first element
                  .ị returns [0ị, 1ị]

            U - Reverse, as the ranges yielded by .ị are "reversed"

Husk, 11 bytes


Try it online!

         ηf     # get truthy indices
     ġo=→       # group runs of adjacent values
m               # then, for each group
 §e←→           # get the first & last elements

05AB1E, 12 bytes

Uses 0/1 for F/T.


Try it online!

Åγ run-length encodes the input, pushing the chunk elements and the chunk lengths.
takes the cumulative sum of the chunck lengths and prepends a 0.
ü2 creates pairs of all adjacent numbers in this list.
s swaps to the list of chunk elements.
Ï selects each pair which is at the same index as a truthy chunk. The selected pairs are now the half-inclusive truthy range [a, b).
€ε iterates over every number in every range, and N- subtracts the 0-based index from each number to get the inclusive ranges.

Try it with step-by-step output!


Vyxal, 9 bytes


Try it Online!


PowerShell, 82 bytes

("$args"|sls 't+'-A).Matches|%{if($_){'{0},{1}'-f$_.Index,($_.Index+$_.Length-1)}}

Regex solution, using MatchInfo object's properties.


PS > .\BoolRange.ps1 'F'

PS > .\BoolRange.ps1 'T'


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.