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)

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


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


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.


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,


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

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

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

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.


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

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.

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.


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>


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

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.


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 .


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

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.


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

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

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.


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

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

0

Mathematica, 45 bytes

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

Não é particularmente interessante; usa um builtin.


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]))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.