Encuentra rangos de valores verdaderos en una lista

26

Reto:

Escriba una función o programa que acepte una lista de valores booleanos y devuelva todos los rangos de True.

Casos de prueba:

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

Reglas:

  • Puede elegir cómo se codifica la entrada, por ejemplo, una lista, matriz, cadena, etc.
  • La salida debe codificarse como una lista de me gusta de lista o una cadena que lo muestre, por lo que matrices, listas, tuplas, matrices, vectores, etc.
  • Los valores booleanos deben codificarse como constantes, pero de lo contrario se permite cualquier conversión simple de T / F a las constantes deseadas
  • EDITAR: eval o similar durante el tiempo de ejecución está permitido.
  • No olvides explicar cómo se pasa la entrada al programa / función y dar su entrada / salida para los casos de prueba
  • Conversión al formato de entrada deseado sin contar
  • Las lagunas estándar no están permitidas
  • Si su idioma tiene una función para hacer esto, no está permitido
  • No aceptaré mi propia presentación
  • EDITAR: El formato de salida es flexible. Si no se imprime una lista o similar, los valores de rango deben estar separados por un carácter no numérico y también por separado.

Tanteo:

  • La puntuación está en bytes, a menos que no sea adecuada para su idioma (como los códeles en Piet)
  • La puntuación más baja gana

Hay una buena flexibilidad en la entrada y salida, pero las soluciones en las que T / F se reemplazan con funciones que hacen todo el trabajo no están permitidas.

Depuración

Si escribe el suyo en Haskell o puede llamarlo desde Haskell, lo siguiente verificará su función / programa:

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)
Michael Klein
fuente
1
Puede que me falte algo, pero no veo una descripción de cómo se representa un rango en la salida.
Peter Taylor
1
¿Se puede indexar la salida?
LegionMammal978
¿Pueden las gamas ser medio exclusivas?
lirtosiast
1
@ LegionMammal978 Solo si su idioma predeterminado es 1 indexado, por ejemplo Mathematica
Michael Klein
@ThomasKwa No, eso parece muy diferente para los casos de "borde"
Michael Klein

Respuestas:

7

Pyth, 17 16 bytes

fT.b*Y,~+ZNtZrQ8

Utiliza un poco de magia de contador post-asignación elegante junto con la codificación de longitud de ejecución.

Toma de entrada como una matriz de 0s y 1s, por ejemplo [1, 1, 0, 1, 0]. Salidas como en el desafío, por ejemplo [[0, 1], [3, 3]].

Banco de pruebas

orlp
fuente
Agregué una suite de prueba. Si se aprueba la edición y nadie abre, tiene la respuesta válida más corta
Michael Klein
9

Pyth, 18 bytes

CxR.:++~Zkz02_B_`T

Banco de pruebas

Verdadero se representa como 1, Falso como 0.

Los rangos están representados inclusivamente.

isaacg
fuente
¿Puedes agregar una explicación?
lirtosiast
Claro, en otro momento.
isaacg
7

Retina , 82 34 27 bytes

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

S_`:

La línea vacía debe contener un solo espacio.

La entrada es una cadena plana de _para verdadero y :para falso. La salida es pares separados por espacios, cada uno en una línea separada.

Pruébalo en línea.

Explicación

El golf pesado de 82 a 27 bytes fue posible mediante la elección inteligente de la representación de verdadero y falso. Elegí un carácter de palabra _, (que no es un dígito) para verdadero y un carácter que no es de palabra,, :(que no necesita escapar) para falso. Eso me permite detectar los extremos de los rangos como límites de palabras.

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

Hacemos coincidir un límite de palabra. Queremos reemplazar ese límite con el índice correspondiente del valor de verdad. En principio, eso es bastante fácil con la $#característica reciente de Retina , que cuenta el número de capturas de un grupo. Simplemente capturamos a cada personaje frente a esa posición en un grupo. Al contar esos personajes obtenemos la posición. El único inconveniente es que los extremos del rango están desactivados por uno ahora. De hecho, queremos el índice del personaje delante del partido. Eso también se soluciona fácilmente al hacer coincidir opcionalmente un _que no se captura, omitiendo así un personaje cuando estamos al final de un rango.

_+
<space>

Ahora reemplazamos todas las series de guiones bajos con un espacio. Es decir, insertamos un espacio entre el principio y el final de cada rango, mientras eliminamos los guiones bajos.

S_`:

Eso deja los dos puntos (y aún necesitamos separar pares). Hacemos eso dividiendo la cadena completa en líneas alrededor de cada colon. El Smodo dividido activo, y _suprime los segmentos vacíos de modo que no se obtienen toneladas de líneas vacías cuando tenemos series de dos puntos.

Martin Ender
fuente
5

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

Salida de ejemplo:

2 3; 7 16; 18 18;

Un enfoque directo, no incorporado. Rastrea el valor actual xy el valor anterior p. Cuando estos son diferentes, hemos cambiado de ejecución. Al cambiar 0a 1, imprime el índice actual i. Al cambiar 1a 0, imprime el índice actual menos uno seguido de un punto y coma.

El ifes bastante maloliente. Quizás la recursión sería mejor

xnor
fuente
5

MATL , 17 18 20 bytes

j'T+'1X32X34$2#XX

Utiliza la versión actual (9.1.0) del lenguaje / compilador.

La entrada es una cadena que contiene caracteres Ty F. La salida es una tabla de dos filas, donde cada columna indica un rango que utiliza la indexación 1, que es el idioma predeterminado.

Gracias a Stewie Griffin por eliminar 2 bytes.

Ejemplo

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

Explicación

Se basa en una expresión regular simple:

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
Luis Mendo
fuente
4

Octava, 43 Bytes

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

find(diff([0,x,0]))encuentra todas las posiciones donde la matriz de entrada cambia entre verdadero y falso. Al transformar esto en una matriz de 2 por n, logramos dos cosas: los cambios de verdadero a falso y de falso a verdadero se dividen en dos filas. Esto hace posible restar 1 y 2 de cada una de esas filas. Restar 1 de la fila uno es necesario porque Octave está indexado 1, no indexado a cero. Restar 2 de la fila dos es necesario porque find(diff())encuentra la posición del primer valor falso, mientras que queremos el último valor verdadero. La parte de resta solo es posible en Octave, no en 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
Stewie Griffin
fuente
1
Buen uso de la radiodifusión!
Luis Mendo
4

CJam, 27 25 bytes

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

Espera entrada como TTFTFT. Pruébalo en línea .

Explicación

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
Sp3000
fuente
4

Japt, 34 31 25 bytes

Intentar un nuevo enfoque realmente funcionó esta vez.

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

Pruébalo en línea!

La entrada es una cadena con Ffor falsey Tfor true. La salida es una matriz de matrices; la representación de cadena hace que se vea como una sola matriz.

Cómo funciona

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

Nota: Ahora veo que varias personas ya habían ideado este algoritmo, pero lo descubrí de forma independiente.

Versión no competitiva, 22 bytes

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

En la última confirmación de GitHub , agregué una nueva característica: un líder ;establece las variables A-J,Len diferentes valores. Ase establece en una matriz vacía, lo que elimina la necesidad de crearlo manualmente.

ETHproducciones
fuente
3

Haskell, 74 bytes

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

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

Cómo funciona:

                               -- 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)]
nimi
fuente
3

J 26 bytes

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

Este es un verbo monádico sin nombre (función unaria) que devuelve una matriz 2D o enteros. Se usa de la siguiente manera.

  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

Explicación

[: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.
Zgarb
fuente
3

Ruby, 39

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

Invocación de muestra:

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

El ..es como rubíes representa rangos inclusivos.

Lo interesante aquí es cómo obtengo el índice del final del rango. Es raro. Creo dinámicamente una expresión regular que coincide con el último carácter del rango, y luego todos los caracteres posteriores y el final de la cadena para forzar la coincidencia correcta. Luego uso =~para obtener el índice de esa expresión regular en la cadena original.

Sospeche que podría haber una forma más corta de hacer esto en Ruby usando las banderas -naF.

histocrat
fuente
2

JavaScript (ES6), 59

Una función anónima, ingresada como una cadena de Ty F, devolviendo la salida como una matriz de matrices

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

PRUEBA

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>

edc65
fuente
Wow, acabo de encontrar la misma solución en Japt y estaba a punto de traducirla a JS. Nice one :)
ETHproductions
2

𝔼𝕊𝕄𝕚𝕟, 18 caracteres / 28 bytes

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

Try it here (Firefox only).

Explicación

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

Haskell, 62 bytes

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

Toma como entrada una lista de 0 y 1.

Dada la lista l, la rellena con 0 en ambos lados y calcula la lista indexada de pares consecutivos. Por ejemplo

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

Luego, extraiga los índices correspondientes a elementos consecutivos (0,1)y (1,0), que son los inicios de bloques de 0 y 1, restando 1 de los inicios de 0 para obtener los extremos de 1, y comprime los resultados.

xnor
fuente
Wow, eso dobla la sintaxis más de lo que pensé que tomaría Haskell. ¿Es equivalente a "fl = let s = zip3 [0 ..] (0: l) (l ++ [0]) en zip [i | (i, 0,1) <- s] [i-1 | (i , 1,0) <- s] "?
Michael Klein
1
@MichaelKlein Sí, aprendí del truco de atar a los guardias de nimi aquí . También es equivalente a la unión más larga a través de lambda f l=(\s->zip[i|(i,0,1)<-s][i-1|(i,1,0)<-s])$zip3[0..](0:l)$l++[0].
xnor
2

Pyth, 19 18 bytes

m-VdU2cx1aV+ZQ+QZ2

Explicación:

             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

Pruébalo aquí .

lirtosiast
fuente
2

Perl, 47 bytes

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

Con las siguientes opciones de perlrun -lpe:

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

Alternativa donde la salida está separada por líneas (34 bytes):

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

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

Casos de prueba:

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

Seguramente hay una solución más corta que esta, pero funciona.

quintapia
fuente
1

Haskell: 123 bytes (Ejemplo, no puede ganar)

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

Menos golfizado:

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)))
Michael Klein
fuente
Incluso cuando no juegues al golf: allTrue s e = and (subList s e)o tal vez allTrue = (and.) . sublist.
nimi
Ok, por una razón que no recuerdo, pensé que eso era más "claro" cuando estaba sin golf ... (Editado)
Michael Klein
1
Oh, claro, las opiniones difieren sobre lo que está "claro". También creo que all (==True) (subList s e)es muy claro.
nimi
1

CJam, 30 bytes

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

Ingrese como una matriz de estilo CJam de 0sy 1s. Salida como una matriz de pares estilo CJam.

Ejecute todos los casos de prueba. (Se encarga de la conversión de los formatos de entrada).

Martin Ender
fuente
1

Japt, 27 bytes

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

Tiene que haber una manera de jugar golf ...

De todos modos, es lo mismo que mi respuesta 𝔼𝕊𝕄𝕚𝕟.

Mama Fun Roll
fuente
Wow, se me ocurrió esta solución ... ¡Buen algoritmo!
ETHproductions
1

APL, 17 caracteres

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

En ⎕IO←0y ⎕ML←3. En inglés:

  • ⍵×⍳⍴⍵: pone a cero los elementos del vector índice siempre que el argumento donde el argumento sea falso
  • ⍵⊂: corta al comienzo de cada serie de verdades y tira las falsas
  • (↑,↑∘⊖)¨: toma el primer y último elemento de cada submatriz
lstefano
fuente
0

PowerShell, 82 bytes

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

Solución de expresiones regulares, utilizando las propiedades del objeto MatchInfo .

Ejemplo

PS > .\BoolRange.ps1 'F'


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

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

Mathematica, 45 bytes

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

No particularmente interesante; usa un incorporado.

Un simmons
fuente
0

Clojure, 109 caracteres

#(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 %)))

Lo primero que me vino a la mente, basado en reducey partition-by.

Caso de prueba sencilla (mapea Ta truey Fa 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]))
NikoNyrh
fuente