Encontre intervalos de valores True em uma lista

26

Desafio:

Escreva uma função ou programa que aceite uma lista de valores booleanos e retorne todos os intervalos de True.

Casos de teste:

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

Regras:

  • Você pode escolher como a entrada é codificada, por exemplo, uma lista, matriz, string, etc.
  • A saída deve ser codificada como uma lista de gostos de lista ou uma sequência que mostre tais matrizes, listas, tuplas, matrizes, vetores, etc.
  • Os valores booleanos devem ser codificados como constantes, mas, caso contrário, qualquer conversão simples de T / F para constantes desejadas é permitida
  • EDIT: eval ou similar durante o tempo de execução é permitido.
  • Não se esqueça de explicar como a entrada é passada para o programa / função e fornecer sua entrada / saída para os casos de teste
  • Conversão para o formato de entrada desejado não contado
  • As brechas padrão não são permitidas
  • Se seu idioma tem uma função para fazer isso, não é permitido
  • Não aceitarei minha própria inscrição
  • EDIT: O formato de saída é flexível. Se não estiver imprimindo uma lista ou semelhante, os valores dos intervalos devem ser separados por um caractere não numérico e também por intervalos separados.

Pontuação:

  • A pontuação está em bytes, a menos que não seja adequado ao seu idioma (como codels em Piet)
  • Menor pontuação ganha

Há um pouco de flexibilidade na entrada e na saída, mas as soluções em que o T / F é substituído por funções que fazem todo o trabalho são proibidas.

Depuração:

Se você escreve o seu em Haskell ou pode chamá-lo em Haskell, o seguinte irá verificar sua função / 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
fonte
1
Talvez esteja faltando alguma coisa, mas não vejo uma descrição de como um intervalo é representado na saída.
22413 Peter Peter
1
A saída pode ser indexada 1?
LegionMammal978
Os intervalos podem ser meio exclusivos?
lirtosiast
1
@ LegionMammal978 Somente se o padrão do seu idioma for 1 indexado, por exemplo Mathematica
Michael Klein
@ThomasKwa Não, isso parece muito diferente para casos "extremos"
Michael Klein

Respostas:

7

Pitão, 17 16 bytes

fT.b*Y,~+ZNtZrQ8

Usa um contador mágico pós-atribuição sofisticado, juntamente com a codificação da duração da execução.

Toma de entrada como uma série de 0s e 1s, por exemplo [1, 1, 0, 1, 0]. Resultados como no desafio, por exemplo [[0, 1], [3, 3]].

Suíte de teste

orlp
fonte
Eu adicionei uma suíte de teste. Se a edição for aprovada e ninguém furtar, você terá a resposta mais curta e válida.
Michael Klein
9

Pitão, 18 bytes

CxR.:++~Zkz02_B_`T

Suíte de teste

True é representado como 1, False como 0.

As faixas são representadas inclusive.

isaacg
fonte
Você pode adicionar uma explicação?
precisa saber é o seguinte
Claro, em outro momento.
Isaacg
7

Retina , 82 34 27 bytes

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

S_`:

A linha vazia deve conter um único espaço.

Input é uma sequência plana de _para true e :false. A saída é pares separados por espaço, cada um em uma linha separada.

Experimente online.

Explicação

O golfe pesado de 82 até 27 bytes foi possível pela escolha inteligente da representação de verdadeiro e falso. Eu escolhi um caractere de palavra _, (que não é um dígito) para verdadeiro e um caractere :que não seja de palavra (que não precisa ser escapado) para falso. Isso me permite detectar os fins dos intervalos como limites de palavras.

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

Combinamos um limite de palavras. Queremos substituir esse limite pelo índice correspondente do valor de verdade. Em princípio, isso é bastante fácil com o $#recurso recente de Retina , que conta o número de capturas de um grupo. Simplesmente capturamos cada personagem na frente dessa posição em um grupo. Contando esses caracteres, obtemos a posição. O único problema é que as extremidades do intervalo estão fora de um agora. Na verdade, queremos o índice do personagem na frente da partida. Isso também é facilmente corrigido combinando opcionalmente um _que não é capturado, pulando um caractere quando estamos no final de um intervalo.

_+
<space>

Agora substituímos todas as execuções de sublinhados por um espaço. Ou seja, inserimos um espaço entre o início e o final de cada intervalo, enquanto nos livramos dos sublinhados.

S_`:

Isso deixa os dois pontos (e ainda precisamos separar os pares). Fazemos isso dividindo a cadeia inteira em linhas ao redor de cada dois pontos. Os Sativos modo de dividir, e os _Suprime segmentos vazios de tal forma que não recebem toneladas de linhas vazias quando temos corridas de dois pontos.

Martin Ender
fonte
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

Exemplo de saída:

2 3; 7 16; 18 18;

Uma abordagem direta, sem built-ins. Rastreia o valor atual xe o valor anterior p. Quando estes são diferentes, mudamos de execução. Ao mudar 0para1 , imprime o índice atual i. Ao alternar 1para 0, imprime o índice atual menos um seguido por ponto e vírgula.

O ifé muito fedido. Talvez a recursão fosse melhor,

xnor
fonte
5

MATL , 17 18 20 bytes

j'T+'1X32X34$2#XX

Usos a versão atual (9.1.0) do idioma / compilador.

Entrada é uma sequência que contém caracteres TeF . A saída é uma tabela de duas linhas, em que cada coluna indica um intervalo usando a indexação 1, que é o padrão do idioma.

Agradecimentos a Stewie Griffin por remover 2 bytes.

Exemplo

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

Explicação

É baseado em uma simples expressão regular:

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
fonte
4

Oitava, 43 bytes

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

find(diff([0,x,0]))localiza todas as posições em que a matriz de entrada muda entre verdadeiro e falso. Ao remodelar isso em uma matriz de 2 por n, conseguimos duas coisas: As alterações de verdadeiro para falso e de falso para verdadeiro são divididas em duas linhas. Isso torna possível subtrair 1 e 2 de cada uma dessas linhas. Subtrair 1 da linha um é necessário porque a oitava é indexada em 1, e não em zero. Subtrair 2 da linha dois é necessário porque o find(diff())encontra a posição do primeiro valor falso, enquanto queremos o último valor verdadeiro. A parte de subtração só é possível no Octave, não no 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
fonte
1
Bom uso da transmissão!
18136 Luis Mendo
4

CJam, 27 25 bytes

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

Espera entrada como TTFTFT. Experimente online .

Explicação

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
fonte
4

Japonês, 34 31 25 bytes

Tentando uma nova abordagem realmente funcionou desta vez.

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

Experimente online!

Input é uma string com Ffor falsee Tfortrue . Saída é uma matriz de matrizes; a representação da string faz com que pareça uma única matriz.

Como 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: Agora vejo que várias pessoas já criaram esse algoritmo, mas eu o descobri de forma independente.

Versão não concorrente, 22 bytes

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

No último commit do GitHub , adicionei um novo recurso: um líder ;define as variáveis A-J,Lcom valores diferentes. Aé definido como uma matriz vazia, eliminando assim a necessidade de criá-lo manualmente.

ETHproductions
fonte
3

Haskell, 74 bytes

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

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

Como 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
fonte
3

J, 26 bytes

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

Este é um verbo monádico sem nome (função unária) que retorna uma matriz ou números 2D. É usado da seguinte maneira.

  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

Explicação

[: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
fonte
3

Ruby, 39

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

Chamada de amostra:

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

O ..é como rubi representa intervalos inclusivos.

A única coisa interessante aqui é como eu recebo o índice do final do intervalo. É estranho. Crio dinamicamente uma expressão regular que corresponde ao último caractere do intervalo e, em seguida, todos os caracteres subseqüentes e o final da string para forçar a correspondência correta. Então eu uso=~ para obter o índice desse regex na string original.

Suspeita que possa haver uma maneira mais curta de fazer isso no Ruby usando os sinalizadores -naF.

histocrata
fonte
2

JavaScript (ES6), 59

Uma função anônima, entrada como uma sequência de Te Fretornando a saída como uma matriz de matrizes

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

TESTE

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
fonte
Uau, eu apenas vim com a mesma solução no Japt e estava prestes a traduzi-la para JS. Agradável :)
ETHproductions
2

18, 18 caracteres / 28 bytes

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

Try it here (Firefox only).

Explicação

ïħ`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
fonte
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 uma lista de 0 e 1.

Dada a lista l, a preenche com 0 em ambos os lados e calcula a lista indexada de pares consecutivos. Por exemplo

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

Em seguida, extraia os índices correspondentes aos elementos consecutivos (0,1)e (1,0), que são o início dos blocos de 0 e 1, subtraindo 1 do início de 0 para obter o final de 1 e feche os resultados.

xnor
fonte
Uau, isso altera a sintaxe mais do que eu pensava que Haskell levaria. É equivalente a "fl = let s = zip3 [0 ..] (0: l) (l ++ [0]) no zip [i | (i, 0,1) <- s] [i-1 | (i , 1,0) <- s] "?
Michael Klein
1
@ MichaelKlein Sim, eu aprendi sobre o truque de amarrar guardas com o nimi aqui . Também é equivalente à ligação mais longa via lambda f l=(\s->zip[i|(i,0,1)<-s][i-1|(i,1,0)<-s])$zip3[0..](0:l)$l++[0].
xnor 12/01
2

Pitão, 19 18 bytes

m-VdU2cx1aV+ZQ+QZ2

Explicação:

             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

Experimente aqui .

lirtosiast
fonte
2

Perl, 47 bytes

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

Com as seguintes opções de perlrun -lpe:

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

Alternativa em que a saída é separada por linha (34 bytes):

$ perl -pE's/F*(T*)(T)F*/$-[0] $+[1]\n/g;chomp' <<< TTFFFTTTTTTTTTTF
0 1
5 15
andlrc
fonte
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 teste:

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

Certamente, existe uma solução mais curta que essa, mas funciona.

quintopia
fonte
1

Haskell: 123 bytes (exemplo, não é possível vencer)

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 golfe:

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
fonte
Mesmo quando não está jogando golfe: allTrue s e = and (subList s e)ou talvez allTrue = (and.) . sublist.
nimi 11/01
Ok, por uma razão que eu não me lembro, eu pensei que era mais "claro" quando eu era ungolfing ... (Editado)
Michael Klein
1
Ah, claro, as opiniões divergem sobre o que é "claro". Eu também acho que all (==True) (subList s e)é muito claro.
nimi 11/01
1

CJam, 30 bytes

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

De entrada como um arranjo de estilo CJam de 0s e1 s. Saída como uma matriz de pares no estilo CJam.

Execute todos os casos de teste. (Cuida da conversão dos formatos de entrada.)

Martin Ender
fonte
1

Japonês, 27 bytes

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

Tem que haver uma maneira de jogar golfe ...

Enfim, é o mesmo que a minha resposta.

Mama Fun Roll
fonte
Uau, eu mesmo vim com essa solução .... Bom algoritmo!
ETHproductions
1

APL, 17 caracteres

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

Em ⎕IO←0e ⎕ML←3. Em inglês:

  • ⍵×⍳⍴⍵: zere os elementos do vetor de índice, contanto que o argumento em que o argumento seja falso
  • ⍵⊂: cortar no início de cada série de verdades e jogar fora as falsas
  • (↑,↑∘⊖)¨: pegue o primeiro e o último elemento de cada sub-matriz
lstefano
fonte
0

PowerShell, 82 bytes

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

Solução Regex, usando MatchInfo as propriedades do objeto .

Exemplo

PS > .\BoolRange.ps1 'F'


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

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

Mathematica, 45 bytes

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

Não é particularmente interessante; usa um builtin.

A Simmons
fonte
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 %)))

A primeira coisa que me veio à mente, baseada reduceepartition-by .

Caso de teste simples (mapeia Tpara truee Fpara 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
fonte