| Bytes | Lang | Time | Link |
|---|---|---|---|
| 009 | Japt | 201029T155842Z | Shaggy |
| 026 | Perl 5 + M5.10.0 n | 240618T081222Z | Dom Hast |
| 009 | Vyxal | 220806T182302Z | naffetS |
| 6261 | Knight | 220806T180211Z | Jonah |
| 008 | Jelly | 220727T184329Z | Jonathan |
| 011 | Vyxal | 210511T133512Z | xigoi |
| 012 | 05AB1E | 210114T152712Z | ovs |
| 010 | Jelly | 201029T221815Z | xigoi |
| 011 | Husk | 201105T220801Z | Dominic |
| 121 | Java JDK | 201029T164955Z | Conffusi |
| 013 | Jelly | 201029T203701Z | caird co |
| 019 | K oK | 201029T190501Z | coltim |
| 014 | Husk | 201029T173115Z | Razetime |
| 109 | Clojure | 161219T202109Z | NikoNyrh |
| 017 | APL | 160630T174145Z | lstefano |
| 045 | Mathematica | 160213T125759Z | A Simmon |
| 047 | Perl | 160111T233409Z | Andreas |
| 017 | MATL | 160111T215720Z | Luis Men |
| 016 | Pyth | 160111T222450Z | orlp |
| 018 | Pyth | 160111T230452Z | isaacg |
| 082 | PowerShell | 160112T130530Z | beatcrac |
| 039 | Ruby | 160111T224244Z | histocra |
| 018 | Pyth | 160111T181602Z | lirtosia |
| 062 | Haskell | 160112T045653Z | xnor |
| 069 | Python 2 | 160112T040921Z | xnor |
| 025 | Japt | 160111T194641Z | ETHprodu |
| 025 | CJam | 160111T222939Z | Sp3000 |
| 026 | J | 160112T015604Z | Zgarb |
| 027 | Japt | 160112T005338Z | Mama Fun |
| 1828 | 𝔼𝕊𝕄𝕚𝕟 | 160112T003626Z | Mama Fun |
| 027 | Retina | 160111T180807Z | Martin E |
| 030 | CJam | 160111T221611Z | Martin E |
| nan | Haskell 123 bytes Example | 160111T175104Z | Michael |
| 074 | Haskell | 160111T213642Z | nimi |
| 043 | Octave | 160111T213003Z | Stewie G |
| 059 | JavaScript ES6 | 160111T195704Z | edc65 |
| 108 | Python 2 | 160111T185124Z | quintopi |
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ò
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
-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:
- indices of truthy values with no truthy value to their right (run starts); and
- 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ẇ
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-
Åγ 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.
Jelly, 12 11 10 bytes
;0ŻIT’Ðes2
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
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
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
+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':
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.
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:
⍵×⍳⍴⍵: 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
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]].
Pyth, 18 bytes
CxR.:++~Zkz02_B_`T
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
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+`,↪ᵖ[_,$Ꝉ+‡_]
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.
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.