g | x | w | all
Bytes Lang Time Link
009Japt201029T155842ZShaggy
026Perl 5 + M5.10.0 n240618T081222ZDom Hast
009Vyxal220806T182302ZnaffetS
6261Knight220806T180211ZJonah
008Jelly220727T184329ZJonathan
011Vyxal210511T133512Zxigoi
01205AB1E210114T152712Zovs
010Jelly201029T221815Zxigoi
011Husk201105T220801ZDominic
121Java JDK201029T164955ZConffusi
013Jelly201029T203701Zcaird co
019K oK201029T190501Zcoltim
014Husk201029T173115ZRazetime
109Clojure161219T202109ZNikoNyrh
017APL160630T174145Zlstefano
045Mathematica160213T125759ZA Simmon
047Perl160111T233409ZAndreas
017MATL160111T215720ZLuis Men
016Pyth160111T222450Zorlp
018Pyth160111T230452Zisaacg
082PowerShell160112T130530Zbeatcrac
039Ruby160111T224244Zhistocra
018Pyth160111T181602Zlirtosia
062Haskell160112T045653Zxnor
069Python 2160112T040921Zxnor
025Japt160111T194641ZETHprodu
025CJam160111T222939ZSp3000
026J160112T015604ZZgarb
027Japt160112T005338ZMama Fun
1828𝔼𝕊𝕄𝕚𝕟160112T003626ZMama Fun
027Retina160111T180807ZMartin E
030CJam160111T221611ZMartin E
nanHaskell 123 bytes Example160111T175104ZMichael
074Haskell160111T213642Znimi
043Octave160111T213003ZStewie G
059JavaScript ES6160111T195704Zedc65
108Python 2160111T185124Zquintopi

Japt, 14 9 bytes

With input as an array of bits. Takes advantage of the loose output format by reversing the order of each pair. If that's not permitted then replace the o at the end with õT.

ð ü- ËgJò

Try it

Perl 5 + -M5.10.0 -n, 26 bytes

say"@- ","@+"-1while/1+/gc

Try it online!

Vyxal, 9 bytes

ẏ‡?iŻv₍gG

Try it Online!

Knight, 62 61 bytes

;=i 0;=s T;W;=i+i 1=nP;=nEn&|&s n&!s!n;O Is i-i 1=s!s&!sO-i 1

Try it online!

-1 thanks to Steffan

Uses 1 indexing.

how

;=i 0          # Set i = 0
;=s T          # Set s (for "searching for a 1" to true)
;W;=i+i 1=nP   # While reading a line of input "n" and 
               # storing it in n, and incrementing i...
;=nEn          # Coerce "n" to a number, so we can use
               # it as a boolean (string "1" would be false)
&|&s n &!s !n  # If we're "searching" and found a 1 or
               # are not searching and found a 0...
;O Is i-i 1    # output the current index when searching, 
               # or the current index - 1 otherwise.
=s!s           # and toggle "searching" status
&!sO-i 1       # if we end on a 1, output again the
               # final index - 1

Jelly, 8 bytes

Tḟ+¥ⱮØ+Z

A monadic Link that accepts a list and yields a list of start, end pairs of truthy runs (1-indexed, as Jelly is).

Try it online! Or see the test-suite.

How?

Tḟ+¥ⱮØ+Z - Link: list, A
T        - Truthy indices of A -> t
     Ø+  - [1,-1]
    Ɱ    - map (for n in [1,-1]) with:
   ¥     -   last two links as a dyad f(t, n):
  +      -     t add n (vectorises)
 ḟ       -     t filter discard those
       Z - transpose

i.e. get a pair of lists of:

  1. indices of truthy values with no truthy value to their right (run starts); and
  2. indices of truthy values with no truthy value to their left (run ends)

...and transpose that to a list of [run start, run end] pairs.

Vyxal, 12 11 bytes

0J0p¯T⁽‹ẇ2ẇ

Try it Online!

Translation of my Jelly answer.

Explanation

0J0p¯T⁽‹ẇ2ẇ
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

05AB1E, 12 bytes

Uses 0/1 for F/T.

Åγ.¥ü2sÏ€εN-

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!

Jelly, 12 11 10 bytes

;0ŻIT’Ðes2

Try it online!

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

Explanation

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]]

Husk, 11 bytes

m§e←→ġo=→ηf

Try it online!

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

Java (JDK), 181 169 121

a->{int f=-1,p=0;for(int c:a.toCharArray()){if(c<49&f>=0){System.out.println(f+","+~-p);f=-1;}f=c>48&f<0?p:f;p++;}};

Execute:

java T 1100011111111110

Output:

0,1
5,14

Try it online!

Explained

  int f=-1,                               // index of first '1' of current range
      p=0;                                // current position in the input array
  for(int c:a[0].toCharArray()){          // loop over the input from the command line (int & char are exchangeable here
    if(c<49&f>=0){                        // 48='0'; current=0 and we had a '1' range 
      System.out.println(f+","+~-p);      // print first and current-1
      f=-1;                               // we are no longer in a 1 range
    }  
    f=c>48&f<0?                           // 49='1'; if current='1' and is first of new range, 
        p                                 // let f start here
        :f                                // otherwise f unchanged
    p++;                                  // increase current index counter
  }                                       // end of for loop
};                                        // end of function

Edits:

181 -> 169 : interface instead of class; f==-1 -> f<0

169 -> 121 : added suggestions of @ceilingcat and reduced it to a function

121 -> 116 : small, nice improvements, thanks @ceilingcat

Jelly, 13 bytes

TI’kƊ.ịⱮ$ḢẠ?U

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"

K (oK), 19 bytes

+&:'+{y&~x,z}.'-3':

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.

Husk, 14 bytes

§zeW<om←W>`:0Θ

Try it online!

Clojure, 109 chars

#(first(reduce(fn[[r i]p](let[e(+(count p)i)][(if(first p)(conj r[i(dec e)])r)e]))[[]0](partition-by not %)))

The first thing that came to my mind, based on reduce and partition-by.

Simple test case (maps T to true and F to false):

(def f #(first(reduce(fn[[r i]p](let[e(+(count p)i)][(if(first p)(conj r[i(dec e)])r)e]))[[]0](partition-by not %))))
(f (map #(= 'T %) '[F,T,T,F,F,T,T,T]))

APL, 17 chars

{(↑,↑∘⊖)¨⍵⊂⍵×⍳⍴⍵}

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

Mathematica, 45 bytes

SequencePosition[#,{True..},Overlaps->False]&

Not particularly interesting; uses a builtin.

Perl, 47 bytes

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

With the following perlrun options -lpe:

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

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

MATL, 17 18 20 bytes

j'T+'1X32X34$2#XX

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.

Example

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

Explanation

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

Pyth, 17 16 bytes

fT.b*Y,~+ZNtZrQ8

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

Pyth, 18 bytes

CxR.:++~Zkz02_B_`T

Test suite

True is represented as 1, False as 0.

Ranges are represented inclusively.

PowerShell, 82 bytes

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

Regex solution, using MatchInfo object's properties.

Example

PS > .\BoolRange.ps1 'F'


PS > .\BoolRange.ps1 'T'
0,0

PS > .\BoolRange.ps1 'TTFFFTTTTTTTTTTF'
0,1
5,14

Ruby, 39

->s{s.scan(/T+/){p$`.size..s=~/.#$'$/}}

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"]
0..1
3..4
6..8
10..10

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.

Pyth, 19 18 bytes

m-VdU2cx1aV+ZQ+QZ2

Explanation:

             implicit: Q=input
m            map lambda d:
  -V         Vectorized subtraction by [0,1]
     d
     U2     
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
  2

Try it here.

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.

Python 2, 69 bytes

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

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,

Japt, 34 31 25 bytes

Trying a new approach really worked out this time.

V=[]Ur"T+"@Vp[YY-1+Xl]};V

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

;Ur"T+"@Ap[YY-1+Xl]};A

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.

CJam, 27 25 bytes

0qe`{~~{+}{1$+:X(]pX}?}/;

Expects input like TTFTFT. Try it online.

Explanation

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

J, 26 bytes

[:I.&.|:3(<`[/,]`>/)\0,,&0

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

Explanation

[:I.&.|:3(<`[/,]`>/)\0,,&0
                       ,&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.

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.

𝔼𝕊𝕄𝕚𝕟, 18 chars / 28 bytes

ïħ`T+`,↪ᵖ[_,$Ꝉ+‡_]

Try it here (Firefox only).

Explanation

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

Retina, 82 34 27 bytes

\b(?<=(.)*_?)
$#1
_+

S_`:

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.

Explanation

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.

\b(?<=(.)*_?)
$#1

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.

_+
<space>

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.

S_`:

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.

CJam, 30 bytes

0l~0++2ewee{1=$2,=},{~0=-}%2/`

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

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]
  where
    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)))

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)]

Octave, 43 Bytes

@(x)reshape(find(diff([0,x,0])),2,[])-[1;2]

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.

F=0;T=1;
x=[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]

reshape(find(diff([0,x,0])),2,[])-[1;2]
ans =    
    2   12   33   93
    3   19   54   94

x=[T,T,F,F,F,T,T,T,T,T,T,T,T,T,T,F]
reshape(find(diff([0,x,0])),2,[])-[1;2]
ans =    
    0    5
    1   14

JavaScript (ES6), 59

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

x=>x.replace(/T+/g,(a,i)=>o.push([i,a.length+i-1]),o=[])&&o

TEST

f=x=>x.replace(/T+/g,(a,i)=>o.push([i,a.length+i-1]),o=[])&&o

// TEST

arrayOut=a=>`[${a.map(e=>e.map?arrayOut(e):e).join`,`}]`

console.log=x=>O.textContent+=x+'\n'

;[
  'F','T','TTFT','FTTFFTTT','FTTFFFTTTT','TTFFFTTTTTTTTTTF',
  'FFTTFFFFFFFFTTTTTTTTFFFFFFFFFFFFFTTTTTTTTTTTTTTTTTTTTTTFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFTT'
].forEach(t=>console.log(t+'\n'+arrayOut(f(t))+'\n'))
<pre id=O></pre>

Python 2, 108 bytes

l=input();l+=[0];o=[];s=k=0
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
[0]
[]
$ python2 rangesinlists2.py
[-1]
[[0, 0]]
$ python2 rangesinlists2.py
[-1,-1,0,-1]
[[0, 1], [3, 3]]
$ python2 rangesinlists2.py
[0,-1,-1,0,0,-1,-1,-1]
[[1, 2], [5, 7]]
$ python2 rangesinlists2.py
[0,-1,-1,0,0,0,-1,-1,-1,-1]
[[1, 2], [6, 9]]
$ python2 rangesinlists2.py
[-1,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0]
[[0, 1], [5, 14]]
$ python2 rangesinlists2.py
[0,0,-1,-1,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1]
[[2, 3], [12, 19], [33, 54], [93, 94]]

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